-
[Kotlin In Action] Chapter 3 - Defining and calling functionsDev/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의 경우의 수를 대비하도록 지정할 수 있다.
12345678/** 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를 사용하지 않고 작업하기 위한 방법
1234567891011package strings;public class JoinKt {public static String joinToString(...) { ... }}//Java로 Compile될 때에는 위의 형식으로 변환됨import strings.JoinKt;...JoinKt.joinToString(list, ", ", "", "");// Java에서 "Kotlin으로 개발되어 compile된" 최상위 함수를 사용하기 위해서는 위의 형식으로 사용함cs @JvmName 어노테이션을 사용하면 클래스에 특정 클래스명을 설정할 수 있다.
12345// @JvmName Annotation을 사용해 컴파일 시 특정 이름의 클래스로 컴파일되도록 만드는 법// StringFunctions라는 클래스명으로 컴파일됨@file:JvmName("StringFunctions")package stringsfun joinToString(...): String { ... }cs Java에서는 당연히 저 클래스명을 사용한다.
123/* Java */import strings.StringFunctions;StringFunctions.joinToString(list, ", ", "", "");cs 최상위 속성들도 존재한다.
1234567891011121314151617181920var opCount = 0fun 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로 쓰일 수 있지만 외부에서 정의된 것.
12345678910fun 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 해야 한다(불러오기).
123456789101112131415161718/** 기본적인 불러오기*/import strings.lastCharval c = "Kotlin".lastChar()/** *를 사용해 모두 불러오는 것도 가능하다.*/import strings.*val c = "Kotlin".lastChar()/** 불러온 클래스의 이름을 alias로 바꿈* Ex) lastChar -> last*/import strings.lastChar as lastval c = "Kotlin".last()cs 2) Calling extension functions from Java
확장 함수: Receiver Object를 첫 인자로 받는 Static Method
Static Method 사용하듯이 사용하되 첫 argument만 해당 Object를 넘겨주면 된다.
1char c = StringUtilKt.lastChar("Java");cs 3) Utility functions as extensions
다음과 같이 Receiver Type을 확장시켜서 다양하게 사용 가능한 유틸성 Function을 만들 수도 있다.
주의: Type 체크를 항상 하자.
12345678910111213fun 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 가능
12345678910111213open 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 clickedcs 확장 함수는 기본적으로 외부에서 선언된 Static Method이기 때문에 Override할 수 없음
123456fun 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에서 다음과 같이 사용된다.
123View view = new Button();ExtensionsKt.showOff(view);// I'm a view!cs 실제 view는 Button Class의 객체이지만 선언을 View Type으로 했으므로 View.showOff가 호출된다.
5) Extension properties
기존의 Object에 대한 Property(속성) 형식으로 사용할 수 있는 API를 추가한다.
1234567891011121314151617181920212223/* 속성 선언* get,set,constructor가 없기 때문에* 사용을 위해 get을 선언해줘야 한다.*/val String.lastChar: Charget() = get(length - 1)/* 가변 속성 선언* get,set은 정의해줘야 한다.*/var StringBuilder.lastChar: Charget() = get(length - 1)set(value: Char) {this.setCharAt(length - 1, value)}// 실제 사용println("Kotlin".lastChar)// nval 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들을 볼 것
1234567val strings: List<String> = listOf("first", "second", "fourteenth")strings.last()// fourteenthval numbers: Collection<Int> = setOf(1, 14, 2)numbers.max()// 14cs 이렇게 간단하게 사용할 수 있는 함수들이 선언되는 과정
12public fun <T> List<T>.last(): T { /* returns the last element */ }public fun <T : Comparable<T>> Iterable<T>.maxOrNull(): T? { /* finding a maximum in a collection */ }cs 굳이 외울 필요는 없다.
2) Varargs: functions that accept an arbitrary number of arguments
인자의 갯수를 가변으로 줄 수 있게 만들어주는 가변 길이 인자. 대표적인 예: listOf
12345678910111213// 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
1234infix fun Any.to(other: Any) = Pair(this, other)1.to("One")1 to "One"cs to function: Pair를 반환한다.
destructuring declaration은 다음과 같다.
123456789val (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"의 과정은 다음 그림과 같이 진행된다.
내부에서는 componentN 함수를 통해 각 변수들에 값을 할당한다.
https://kotlinlang.org/docs/reference/multi-declarations.html
https://pluu.gitbooks.io/kotlin/content/bd84-b9ac-c120-c5b8.html
Working with strings and regular expressions
1) Splitting strings
다음과 같이 사용 가능
2) Regular expressions and triple-quoted strings
디렉토리 경로를 파싱해보자.
String 확장들로 파싱하는 방법
matchResult.Destructured는 분리 선언
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