Kotlin in Action - 3장

김정욱·2021년 9월 28일
1

Kotlin

목록 보기
2/5
post-thumbnail

해당 글은 Kotlin in Action 도서를 읽으며 정리한 내용입니다

[3장] 함수 정의와 호출

코틀린에서 컬렉션 만들기

  • 코틀린은 자체적으로 컬렉션 기능을 제공하지 않는다
  • 표준 Java 컬렉션을 기반으로 더 많은 기능이 추가된 형태로 사용할 수 있다
    (뒤에 나올 확장 함수 덕분에 이것이 가능)
  • 코틀린으로 작성한 함수를 호출할 때, 파라미터 이름을 명시할 수 있다
    • 하나라도 파라미터 이름을 명시하려면, 혼동을 막기 위해 모두 명시 해야 함
    • 디폴트 파라미터(default parameter)와 함께 유용하게 사용 가능
    • 디폴트 파라미터로 인해 많은 오버로드(함수 중복 선언)을 막을 수 있음
/* 함수 호출시, 이름 명시 */
joinToString(collection, separator = "", prefix = "", postfix = "")

/* 함수 정의시, 이름 명시 + 디폴트 값 지정 */
fun <T> joinToString(
  collection: Collection<T>,
  separator: String = "",
  prefix: String = "",
  postfix: String = ""
)

최상위 함수 / 프로퍼티

  • 최상위 함수
    • class 밖인, 최상위에 위치되어 사용되는 함수
    • Java에서는 클래스 밖에 위치할 수 없었지만, Kotlin에서는 가능
    • 내부적으로 컴파일할 때 새로운 클래스를 정의해 주어서, JVM에 의해 실행될 수 있다
    • Kotlin 컴파일러에 의해 결국 정적(static) 함수로 변환 된다
/* Kotlin */
fun joinToString(...): String { ... }

/* Kotlin 컴파일러에 의해 변환된 결과 => 정적 함수 */
public static String joinToString(...) { ... }
  • 최상위 프로퍼티
    • 파일의 최상위 수준에 위치되어 사용되는 프로퍼티
    • Kotlin 컴파일러에 의해 결국 정적(static) 코드로 변환이 된다
      (정적 필드에 저장)
/* Kotlin */
const val STR = "Kotlin";

/* Kotlin 컴파일러에 의해 변환된 결과 => 정적 변수 */
public static final String STR;

확장 함수 / 프로퍼티

  • 확장 함수
    • 정의
      • 최상위 함수 처럼 클래스 밖에 선언된 함수
      • 클래스에 특정 함수를 확장하기 위한 목적
    • 사용
      • {확장할 클래스의 이름}.{추가하는 함수 이름} 형식으로 함수 선언
      • 확장할 클래스 이름수신 객체 타입 이라고 부름
      • 확장 함수를 호출하기 위해서는 반드시 import를 해줘야 한다
    • 특징
      • 어떤 클래스의 멤버 메소드인 것 처럼 호출 가능
      • 결과적으로, 확장함수는 정적 메소드 호출에 대한 문법적인 편의(syntatic sugar)일 뿐이다
      • 확장 함수를 통해 class를 간결하게 유지할 수 있다
        (class 외부에 위치시킬 수 있기 때문)
    • 확장 함수는 오버라이드(override) 할 수 없다
      • 정적 메소드와 같은 특징을 가진다
      • 클래스의 일부가 아니기 때문에 상속이 안되고, 오버라이드 될 수 없다
/* String클래스에 마지막 문자를 돌려주는 함수를 추가 */
package.strings
fun String.lastChar() : Char = get(length - 1)

// 함수를 호출하는 쪽에서 확장 함수인지, 멤버 함수인지 구분할 수는 없다
// 그리고, 그 여부가 중요한 경우도 거의 없다
import strings.lastChar
val c = "Kotlin".lastChar()
  • 확장 프로퍼티
    • 정의
      • 최상위 프로퍼티 처럼 클래스 밖에 선언된 프로퍼티
      • 클래스에 특정 프로퍼티를 확장하기 위한 목적
    • 사용
      • {확장할 클래스의 이름}.{추가하는 프로퍼티 이름} 형식으로 프로퍼티 선언
    • 특징
      • 기존 클래스의 인스턴스 객체에 필드를 추가할 방법이 X
        -> 상태를 저장하지는 않기 때문
        -> 즉, 그때 그때 evalution
      • 뒷받침하는 필드(프로퍼티의 값을 저장하기 위한 필드)가 없어서 최소한 getter는 정의 해주어야 한다
        -> setter를 작성해도 추가 저장소를 갖는 것은 아니다
      • getter / setter 사용시 수신객체를 받아 짧게 작성 가능
/* 확장 프로퍼티 선언 */
var StringBuilder.lastChar: Char
  get() = get(length - 1) // getter
  set(value: Char){ // setter
    this.setCharAt(length - 1, value)
  } 


/* 확장 프로퍼티 사용 */
val sb = StringBuilder("Kotlin?")
sb.lastChar = "!" // 추가 저장소 X, 기존 저장소 데이터 변경
println(sb) // Kotlin!

컬렉션 처리

  • 가변 길이 인자
    • ...연산자를 통해서, Java에서 메소드를 호출할 때 월하는 개수 만큼 값을 인자로 넘기면, 자바 컴파일러가 값을 넣어주는 기능
    • Kotlin 에서는 vararg 변경자와 *(스프레드 연산자) 를 통해 해당 기능을 사용한다
/* 함수의 정의 */
// vararg 변경자로 여러개의 값을 받을 수 있도록 구현되어 있다
fun listOf<T> (vararg values: T) : List<T> { ... }

/* 사용 */
fun main(args: Array<String>) {
  val list = listOf("args: ", *args) // *는 여기서 스프레드 연산자 이다
  println(list)
}
  • 중위 함수 호출
    • 인자가 하나뿐인 일반 메소드나, 확장 함수를 간략하게 호출하는 기능
    • infix 변경자를 함수에 추가해서 구현할 수 있다
    • 함수의 정의를 간략하게 줄이는 목적을 가진다
/* to 메소드에 중위호출을 위한 infix
   Pair 인스턴스를 반환하며, 이것은 두 원소로 이루어진 순서쌍을 표현한다
   Any는 Java의 Object와 같은 인터페이스 */
infix fun Any.to(other: Any) = Pair(this, other)

/* mapOf()를 통해 map을 만드는 예시 
   to라는 일반 메서드를 중위 호출로 사용하는 것이다 */
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
  • 구조 분해 선언
    • 객체가 가지고 있는 값에서 필요한 값들만 바로 추출하는 기능
    • JS의 구조 분해 / 비구조화 할당과 유사
/* to의 반환값인 Pair에서 number, name이라는 필드를 바로 추출하는 것 */
val (number, name) = 1 to "one"

문자열과 정규식 다루기

  • Kotlin 문자열은 Java 문자열을 포함하며 추가 기능 제공
    (확장 함수를 통해 기능이 추가되어 있다)
  • 문자열 나누기
    • Java에서는 string.split() 의 실제 파라미터가 정규식(regex)
    • Kotlin에서는 정규식(regex)과 일반 텍스트 모두 가능
/* .과 -로 split하는 정규식 */
println("12.345-6.A".split("\\.|-").toRegex())

/* 여러개의 구분 문자열을 받아서 문자열을 나눌 수 있다 => Java는 불가능 */
println("12.345-6.A".split(".","-').toRegex())
  • 3중 따옴표 활용
    • 문자열 이스케이프를 피하기 위해서 사용 가능
    • 줄 바꿈을 표현할 때 그대로 표현 가능
    • Kotlin에서는 정규식 없이도 문자열을 쉽게 파싱할 수 있다
val Str : String = "/Users/Desktop/hue.zip"

fun ParsePath(path: String){
  val directory = path.substringBeforeLast("/")   // "/Users/Desktop"
  val fullName = path.substringAfterLast("/")  // hue.zip
  val fileName = fullName.substringBeforeLast(".") // hue
  val extension = fullName.substringAfterLast(".") // zip
}

[ 요약 ]

  • Kotlin은 자체 컬렉션 클래스를 정의하지 않고, Java 클래스확장해서 사용한다
  • 함수 파라미터디폴트 값을 정의하면, 오버로딩한 함수를 정의할 필요성이 줄어든다
  • 이름 붙인 인자를 사용하면, 함수 호출의 가독성향상시킬 수 있다
  • Kotlin 파일에서 클래스 밖최상위 함수최상위 프로퍼티를 선언할 수 있다
  • 확장 함수확장 프로퍼티를 사용하면, 외부 라이브러리의 클래스포함해서 확장할 수 있다
  • 중위 호출을 통해서 인자가 하나 밖에 없는 메소드확장 함수를 깔끔하게 사용할 수 있다
  • Kotlin은 정규식일반 문자열을 처리할 때 유용한 다양한 문자열 처리 함수를 제공한다
  • Java 문자열에선 많은 이스케이프가 필요할 때, Kotlin은 3중 따옴표 문자열로 간단하게 표현할 수 있다
profile
Developer & PhotoGrapher

0개의 댓글