ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin In Action] Chapter 3 - Defining and calling functions
    Dev/Kotlin 2021. 1. 9. 04:41

    * 해당 포스트는 "Kotlin In Action" 책을 읽고 난 이후의 정리 내용입니다.

      자세한 내용은 "Kotlin In Action" 책을 통해 확인해주세요.

     

    Function들을 선언/사용하는 방법에 대해 다룸

    Creating collections in Kotlin(Kotlin에서 Collection 만들기)

    Collection 생성은 ~Of의 형식으로 이루어진다.

    Set을 생성할 경우: setOf

    Java와의 상호작용을 위해 Java의 standard Collections을 사용한다.

    이에 더해, 이 Collections를 활용해 Java보다 더 많은 걸 할 수 있다.

    해당 예제에서는 last, maxOrNull을 활용해 마지막, 최대값을 화면에 출력한다.

     

    Making functions easier to call(함수를 더 쉽게 호출하기)

    사용할 예제: Collection의 내용을 특정 구분자를 사용해 toString 결과 반환

    Collection, separator, Prefix, Postfix를 Argument로 넘겼을 때 이를 합침

     

    1) Named arguments

    Argument에 function의 이름을 명시하는 것.

     

    2) Default parameter values

    기본값을 설정하는 것. 특정 인자를 넘겨주지 않고도 Function을 사용할 수 있게 해준다.

    🛑Kotlin으로 작성한 Function을 Java에서 사용해야 할 때, Kotlin Function에 @JvmOverloads 어노테이션을 사용해 모든 Method의 경우의 수를 대비하도록 지정할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    /* 
     * JvmOverloads 어노테이션을 통해 Java에서 사용할 수 있게 되는 Method들
     */
    String joinToString(Collection<T> collection, String separator,String prefix, String postfix);
    String joinToString(Collection<T> collection, String separator,String prefix);
    String joinToString(Collection<T> collection, String separator);
    String joinToString(Collection<T> collection);
     
    cs

    요런식으로!

     

    3) Getting rid of static utility classes: top-level functions and properties

    StringUtils 같은 Util성 Class를 사용하지 않고 작업하기 위한 방법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package strings;
     
    public class JoinKt {
      public static String joinToString(...) { ... }
    }
    //Java로 Compile될 때에는 위의 형식으로 변환됨
     
    import strings.JoinKt;
    ...
    JoinKt.joinToString(list, ", """"");
    // Java에서 "Kotlin으로 개발되어 compile된" 최상위 함수를 사용하기 위해서는 위의 형식으로 사용함
    cs

     

    @JvmName 어노테이션을 사용하면 클래스에 특정 클래스명을 설정할 수 있다.

     

    1
    2
    3
    4
    5
    // @JvmName Annotation을 사용해 컴파일 시 특정 이름의 클래스로 컴파일되도록 만드는 법
    // StringFunctions라는 클래스명으로 컴파일됨
    @file:JvmName("StringFunctions")
    package strings
    fun joinToString(...): String { ... }
    cs

     

    Java에서는 당연히 저 클래스명을 사용한다.

     

    1
    2
    3
    /* Java */
    import strings.StringFunctions;
    StringFunctions.joinToString(list, ", """"");
    cs

     

    최상위 속성들도 존재한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var opCount = 0
     
    fun performOperation() {
      opCount++
      // ...
    }
     
    fun reportOperationCount(){
      println("Operation performed $opCount times")
    }
     
    val WINDOW_LINE_SEPARATOR = "\r\n"
    /* val은 Java에서 Getter 사용 가능, var는 Getter/Setter 사용 
     * JoinKt.getWINDOW_LINE_SEPARATOR()
     */
     
    const val UNIX_LINE_SEPARATOR = "\n" // JoinKt.UNIX_LINE_SEPARATOR
    // const val == Java의 public static final
    // String과 같은 primitive 형식에서만 사용 가능하다.
    // public static final String UNIX_LINE_SEPARATOR = "\n"; 와 동일한 의미
    cs

     

    Adding methods to other people’s classes: extension functions and properties

    Extension Function: Class의 멤버 method로 쓰일 수 있지만 외부에서 정의된 것.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fun String.lastChar() : Char = this.get(this.length - 1)
    /* String Class의 lastChar() 선언
     * String: Receiver Type
     * this: Receiver Object
     */ 
     
    println("Kotlin".lastChar())
    /* String.lastChar() : Char = "Kotlin".get("Kotlin".length-1)
     * 로 이해하면 될 듯 하다.
     */
    cs

     

    함수 내에서 객체의 Method, 내부 Property에 접근 가능

    (Public만 가능)

    확장 함수보다 Member 함수가 우선

     

    1) Imports and extension functions

    확장 함수 사용을 위해선 Import 해야 한다(불러오기).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /*
     * 기본적인 불러오기 
     */
    import strings.lastChar
    val c = "Kotlin".lastChar()
     
    /*
     * *를 사용해 모두 불러오는 것도 가능하다.
     */
    import strings.*
    val c = "Kotlin".lastChar()
     
    /*
     * 불러온 클래스의 이름을 alias로 바꿈
     * Ex) lastChar -> last
     */
    import strings.lastChar as last
    val c = "Kotlin".last()
    cs

     

    2) Calling extension functions from Java

    확장 함수: Receiver Object를 첫 인자로 받는 Static Method

    Static Method 사용하듯이 사용하되 첫 argument만 해당 Object를 넘겨주면 된다.

    1
    char c = StringUtilKt.lastChar("Java");
    cs

     

    3) Utility functions as extensions

    다음과 같이 Receiver Type을 확장시켜서 다양하게 사용 가능한 유틸성 Function을 만들 수도 있다.

    주의: Type 체크를 항상 하자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    fun Collection<String>.join(
      separator: String = ", ",
      prefix: String = "",
      postfix: String = ""
    ) = joinToString(separator, prefix, postfix)
     
    // 이건 가능
    println(listOf("one", "two", "eight").join(" "))
    // one two eight
     
    // 이건 불가능
    listOf(1, 2, 8).join()
    // Error: Type mismatch: inferred type is List<Int> but Collection<String> was expected.
    cs

     

    4) No overriding for extension functions

    Class의 Function은 Overriding 가능

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    open class View {
      open fun click() = println("View clicked")
    }
     
    // View 상속 받음
    class Button: View() {
      override fun click() = println("Button clicked")
    }
     
    // 실제 사용
    val view: View = Button()
    view.click()
    // Button clicked
    cs

     

    확장 함수는 기본적으로 외부에서 선언된 Static Method이기 때문에 Override할 수 없음

    1
    2
    3
    4
    5
    6
    fun View.showOff() = println("I'm a view!")
    fun Button.showOff() = println("I'm a button!")
    /* val view: View = Button()
     * view.showOff()
     * I'm a view!
     */
    cs

    Receiver Type에 따라 확장 함수가 결정된다.

    Compile된 확장 함수는 Java에서 다음과 같이 사용된다.

    1
    2
    3
    View view = new Button();
    ExtensionsKt.showOff(view);
    // I'm a view!
    cs

    실제 view는 Button Class의 객체이지만 선언을 View Type으로 했으므로 View.showOff가 호출된다.

     

    5) Extension properties

    기존의 Object에 대한 Property(속성) 형식으로 사용할 수 있는 API를 추가한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /* 속성 선언
     * get,set,constructor가 없기 때문에
     * 사용을 위해 get을 선언해줘야 한다.
     */
    val String.lastChar: Char
      get() = get(length - 1)
     
    /* 가변 속성 선언
     * get,set은 정의해줘야 한다.
     */
    var StringBuilder.lastChar: Char
      get() = get(length - 1)
      set(value: Char) {
        this.setCharAt(length - 1, value)
      }
     
    // 실제 사용
    println("Kotlin".lastChar)
    // n
    val sb = StringBuilder("Kotlin?")
    sb.lastChar = '!'
    println(sb)
    // Kotlin!
    cs

     

    Working with collections: varargs, infix calls, and library support

     

    1) Extending the Java Collections API

    Java와 같은 클래스이지만, 좀 더 확장된 API들을 볼 것

    1
    2
    3
    4
    5
    6
    7
    val strings: List<String> = listOf("first", "second", "fourteenth")
    strings.last()
    // fourteenth
     
    val numbers: Collection<Int> = setOf(1, 14, 2)
    numbers.max()
    // 14
    cs

    이렇게 간단하게 사용할 수 있는 함수들이 선언되는 과정

    1
    2
    public fun <T> List<T>.last(): T { /* returns the last element */ }
    public fun <: Comparable<T>> Iterable<T>.maxOrNull(): T? { /* finding a maximum in a collection */ }
    cs

    굳이 외울 필요는 없다.

     

    2) Varargs: functions that accept an arbitrary number of arguments

    인자의 갯수를 가변으로 줄 수 있게 만들어주는 가변 길이 인자. 대표적인 예: listOf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // listOf의 선언 내용
    fun listOf<T>(vararg values: T): List<T> { ... }
     
    // 실제 사용 시
    fun main(args: Array<String>) {
      val list = listOf(2, 3, 5, 7, 11)
     
      /* 배열을 listOf에 넣을 경우 * 표시를 통해
       * 펼쳐서 넣는다.
       */
      val list = listOf("args: ", *args)
      println(list)
    }
    cs

     

    3) Working with pairs: infix calls and destructuring declarations

    중위 호출: infix

    1
    2
    3
    4
    infix fun Any.to(other: Any) = Pair(this, other)
     
    1.to("One")
    1 to "One"
    cs

    to function: Pair를 반환한다.

     

    destructuring declaration은 다음과 같다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    val (number, name) = 1 to "one"
     
    for ((index, element) in collection.withIndex()) {
      println("$index: $element")
    }
     
    // mapOf 선언 과정. varang을 사용해 Pair들을 묶음
    fun <K, V> mapOf(vararg values: Pair<K, V>): Map<K, V>
     
    cs

    1 to "one"의 과정은 다음 그림과 같이 진행된다.

    Destructuring Declaration의 과정

    내부에서는 componentN 함수를 통해 각 변수들에 값을 할당한다.

    https://kotlinlang.org/docs/reference/multi-declarations.html

     

    Destructuring Declarations - Kotlin Programming Language

     

    kotlinlang.org

    https://pluu.gitbooks.io/kotlin/content/bd84-b9ac-c120-c5b8.html

     

    분리 선언 · Kotlin 개인 정리

     

    pluu.gitbooks.io

     

    Working with strings and regular expressions

     

    1) Splitting strings

    다음과 같이 사용 가능

     

    2) Regular expressions and triple-quoted strings

    디렉토리 경로를 파싱해보자.

     

    String 확장들로 파싱하는 방법

    어떻게 했을까?(출처: Kotlin in Action)

     

    matchResult.Destructured는 분리 선언

    정규 표현식을 사용해 파싱(출처: Kotlin in Action)

     

    3) Multiline triple-quoted strings

    escaping characters(특히 \ 요놈)을 사용하지 않고도 String을 표현하기 

    문자열 템플릿 표현 가능("$"는 $('$')의 형식으로 표현해야 함)

     

    Making your code tidy: local functions and extensions

    중복되는 코드를 줄이기 위한 방법

    첫 예: 일반적으로 많이 사용되는 방법

    시작: 로컬 함수 사용

    추가 수정: 외부 함수의 파라메터를 직접 사용

    마지막: 외부 함수 사용

     

    'Dev > Kotlin' 카테고리의 다른 글

    [Kotlin In Action] Chapter 5 - Programming with lambdas  (0) 2021.01.16
    [Kotlin In Action] Chapter 1  (0) 2020.12.30

    댓글

Designed by Tistory.