'intelliJ Edu'에 해당되는 글 2건

2. Conventions

Convention 에는 "관례" 라는 뜻이 있다...

일단 귀찮으니 넘어가자.

 

1) Comparison

첫 번째 문제는 Comparison 이라는 문제다.

여기서 핵심은 

operator 를 overriding 할 수 있다는 개념이다.

 

클래스 내에서 함수를 override 할 때는 operator 키워드를 붙여줄 필요는 없다.

 

Comparable 을 상속해서 , compareTo 함수를 오버라이딩 해주면 끝.

 

이 compareTo 는 operator 에서 <  ==  > 등을 비교하는데 쓰인다.

 

2) In Range

 

이 문제는 보자마자 뭔 개소리지?? 하는 느낌을 주었다.

애초에 자바에 in 같은 키워드가 없기 때문이다. (적어도 난 안쓴다.)

 

쿼리로 따지면 Between 같은 느낌의 연산자이다.

 

"연산자" 이다. < > == 같은 연사자.

 

따라서 연산자 오버라이딩을 하면 된다.

 

Range

A range defines a closed interval in the mathematical sense: it is defined by its two endpoint values which are both included in the range. Ranges are defined for comparable types: having an order, you can define whether an arbitrary instance is in the range between two given instances. The main operation on ranges is contains, which is usually used in the form of in and !in operators.

To create a range for your class, call the rangeTo() function on the range start value and provide the end value as an argument. rangeTo() is often called in its operator form ...

 

class DateRange(val start: MyDate, val endInclusive: MyDate){
    operator fun contains(item: MyDate): Boolean =
            item >= start && item <= endInclusive
}

fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
    return date in DateRange(first, last)
}

이 문제는 이런 식으로 풀면 된다.

 

DateRange 라는 클래스를 만들고, 이 클래스의 main constructor 는 start 와 endinclusive 를 받는다.

그리고 자기가 갖고 있는 start와 endEnclusive 로 넘어오는 MyDate instance 가 범위 안에 속하는지 아닌지를 반환하는 contains 함수를 정의 해준다. 

 

여기서 알 수 있는 것은, "operator" 키워드를 사용해서, 타 클래스의 연산에 관여할 수 있는 클래스를 만들 수 있다는 것이다.

또한 MyDate는 이 전 문제 (1번) 에서 재 정의한 compareTo 함수를 갖고 있다는 것을 명심하자.

 

1) compareTo  로 대소를 배교할 수 있는 클래스(MyDate) 를 만들게 됨.

2) 이제 대소를 비교할 수 있으니 contains 함수도 만들 수 있음. in 연산자를 오버라이딩 한 클래스가 대신 이것을 처리 해 줌.

 

 

3) RangeTo

 

확장 함수로 연산자 오버로딩을 할 수 있다.

이 전 2번 문제에서는 

date in DateRange(first,last) ... 방식으로 범위 안에 속하는지를 검사 했지만.

 

date in first..last 형식으로 이를 바꾸는 것이다.

 

date 도 first 도 last 도 모두 MyDate 클래스의 인스턴스이다.

 

.. 을 사용하기 위해서는 rangeTo operator 를 만들어 줘야 한다.

 

operator fun MyDate.rangeTo(other: MyDate) = DateRange(this, other)

class DateRange(override val start: MyDate, override val endInclusive: MyDate): ClosedRange<MyDate>

 

위와 같이, operator fun MyDate.rangeTo(other: MyDate) = DateRange(this, other)

로 만들면 된다.

 

2단원 부터 갑자기 난이도가 올라가는 면이 있는데, 대부분이 오버라이딩에 관련된 문제인데 함수의 원형을 알기 힘들기 때문이다.

 

일단 문서(docs)를 타고 올라가서 rangeTo 의 틀을 찾아보자.

 

 

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/index.html

 

kotlin.ranges - Kotlin Programming Language

 

kotlinlang.org

여기에 가서 rangeTo 를 찾아보자.

 

ClosedRange 타입의 인스턴스를 반환해야 함을 알 수 있다.

 

DateRange 클래스는 현재 ClosedRange<MyDate> 를 상속하고 있다.

따라서 DateRange 인스턴스를 만들어서 반환하면 되는구나? 라는 것을 생각할 수 있다.

 

여기서 다시 정리해보자.

 

1. compareTo  로 MyDate 클래스의 인스턴스는 대소비교가 가능해짐

2. DateRange 라는 클래스로 contains 를 오버로딩 하면 in 연산자를 사용할 수 있음.

3. rangeTo 를 만들면 first..last 형식으로 쓸 수 있음. rangeTo 의 반환형은 뭐다? -> ClosedRange 다.

 

그럼 쉽게 예상할 수 있을 것이다. ClosedRange 를 상속 받으면 무엇을 오버라이딩 해줘야 할까? -> contains다.

결국 우리가 2번에서 만든 contains 함수를 갖는, DateRange instance를 반환하게 하는 것이 rangeTo 다.

 

따라서..

 

date in DateRange(first,last)  = date in first..last

 

first..last = first.ragneTo(last) = DateRange(first, last)

 

4) For loop

in 은 단순히 대소 비교를 통해, 범위 안에 값이 들어가는지 확인만 하는 것은 아니다. (아닌가?_

 

for 문 안에서도 사용될 수 있다.

 

예를 들면

 

for(date in firstDate..secondDate) {

 

}

와 같이 사용된다.

 

하지만 여기서는 같은 in 키워드여도 다른 것이 필요하다. 단순한 ClosedRange 가 아닌, Iterable 을 상속해야 하며.

Iterabe 인터페이스를 구현하면, Iterator를 반환해야 하고.

 

이 Iterator를 반환하기 위해 새로운 클래스를 만들어야 한다.

 

그냥 Iterator를 anonymous object로 전달하자 무한 루프에 빠져 버렸다. (다른 요인일 수도 있다.)

anonymous object로 만들지 말고, 클래스를 하나 만들고, 인스턴스로 Iterator를 하나 만들어서 뱉어주니 잘 작동했다.

 

 

class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate>{
    override fun iterator(): Iterator<MyDate> = DateIterator(this)
}

class DateIterator(val dateRange:DateRange) : Iterator<MyDate> {
    var current: MyDate = dateRange.start
    override fun next(): MyDate {
        val result = current
        current = current.nextDay()
        return result
    }
    override fun hasNext(): Boolean = current <= dateRange.end
}

fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
    for (date in firstDate..secondDate) {
        handler(date)
    }
}

 

이런 식으로 작서 ㅇ되는데...

 

firstDate..secondDate 를 보면 알 수 있듯이, rangeTo 연산자를 오버라이딩 했다.

rangeTo 함수는 이전 3번처럼 DateRange 인스턴스를 반환하다. DateRange 는 Iterable 을 구현한 클래스이다.

 

Iterator 는 next 와 hasNext 함수를 상속해줘야 한다. 살짝 IntelliJ의 자동 완성 기능의 도움을 받으면 쉽게 오버라이딩 할 함수의 틀을 만들 수 있다.

 

5) Operator overloading

 

오버로딩과 오버라이딩의 차이는 잘 알 것이다.

 

보통 부모의 함수를 상속받아, 자기 껄로 대체 하는것을 오버라이딩이라고 하고.

함수 이름은 같은데 매개변수가 다른 여러 함수를 만드는 것을 오버로딩이라고 한다.

 

오버라이딩은 런타임 시에, 오버로딩은 컴파일 시에 정의 된다... 

 

간략히 여기 까지만 설명 하고.

 

연산자 오버라이딩에서 왜 갑자기 연산자 오버로딩이 제목이 된 걸까? 이를 활용하는 것이 이번 문제의 핵심이자. 정말 재밌는 문제다.

 

난 못 풀었다.

 

6) Destructing declarations.

 

자바스크립트에 "구조 분해 할당" 이란 것이 있다.

 

그거랑 비슷 한건데,

fun isLeapDay(date: MyDate): Boolean {

val (year, month, dayOfMonth) = date

// 29 February of a leap year
return year % 4 == 0 && month == 2 && dayOfMonth == 29
}

 

이렇게 있을 때 MyDate 의 필드 값들이 year, month, dayOfMonth 에 분해돼 들어가는 느낌을 주는... 

 

이것 또한 연산자로 지정해 줘야 한단다...

 

다음과 같다.

 

class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {
    operator fun component1(): Int {
        return year
    }
    operator fun component2(): Int {
        return month
    }
    operator fun component3(): Int {
        return dayOfMonth
    }
}

componentN() 을 정의해주면 된다.

N 에 1~N 까지으 숫자가 들어간다.

 

6) Invokable

 

별 거 없는 문제인데 한 번 기억해두면 좋을 요소가 하나는 있다.

 

class Invokable {
    var numberOfInvocations: Int = 0
        private set
    operator fun invoke(): Invokable {
        numberOfInvocations++
        return this
    }
}

fun invokeTwice(invokable: Invokable) = invokable()()

짜잔.

 

invoke 라는 연산자를 오버라이딩하면..

인스턴스에다가 () 를 붙여서 함수처럼 쓸 수 있다...  위에 invokeTwice 는 말 그대로 invoke 두번 한거다.

 

여기서 private set 부분을 한번 보고 넘어가자.

 

 

Kotlin 에서는 클래스 안에 var a = 3 이런 식으로 "필드" 를 선언해 놓으면 자동으로

get 과 set 함수가 생긴다.

 

자바에서는 아마 @Getter @Setter 등을 붙이거나. (lombok 사용 시에) 직접 만들어야 했을 것이다.

 

만약 상수 선언을 의미하는 val 을 쓴다면? setter 가 생기지 않는다.

 

위에서 필드 선언 부분 아래에서 private set 부분을 확인할 수 있다.

set 함수를 private으로 만든 것이다. var 로 선언했기 때문에 값이 변할 수는 있지만, 이 값을 외부에서 직접 특정 값으로 수정하지는 못하게 한 것이다.

 

이 부분만 집고 넘어가자.

 

2단원은 이렇게 마친다.

 

블로그 이미지

맛간망고소바

,

1. Introduction

1.1 Hello, World!

 

코틀린에서는 function을 다음과 같이 선언할 수 있다.

fun start(): String = "OK"

String 을 반환형으로 사용하는, 파라미터를 받지 않는 start 함수다.

 

https://kotlinlang.org/docs/reference/basic-syntax.html#defining-functions

 

Basic Syntax - Kotlin Programming Language

 

kotlinlang.org

링크가 걸려있다. function 을 여러 방법으로 선언할 수 있다.

 

1.2 Java to Kotlin conversion

자바 코드를 자동으로 코틀린 코드로 바꿔주는 것을 보여주는 예제다.

그냥 JavaCode를 복사해서 붙여넣으면 끝이다. Java to Kotlin Converter의 힘을 감상하기만 하면 끝.

 

1.3 Named arguments

함수를 직접 써보는 예제다. 코틀린은 함수에 파라미터를 넘길 때, 파라미터 이름을 지정해서 넘길 수 있다.

이름을 지정 안하면 순서대로 넘어간다.

 

fun joinOptions(options: Collection<String>) = options.joinToString(", ", "[", "]")

 

코틀린의 Collection은 기본적으로 자바와 같다고 보면 된다. 여기서 더 편리한 기능 확장이 추가돼 있다.

콜렉션이 넘어오면, 인스턴스로 함수를 호출한다.  위와 같이 호출 할 수도 있고,

 

fun joinOptions(options: Collection<String>) = options.joinToString(separator = ", ",
prefix = "[",
postfix = "]")

 

이런 식으로도 호출 할 수 있다.

 

또한 함수를 선언 시에 Default Argument 를 사용할 수 있다.

 

fun 함수이름(a: Int = 1, b: Int = 2) = a + b

이런 식으로 해 놓으면 파라미터에 아무것도 넘어가지 않을 때, 기본 값을 사용한다.

 

"코틀린은 함수 선언시에 기본 값을 지정할 수 있다. 또한 함수 호출 시에 파라미터 이름과 함께 넘길 수 있다."

 

1.4 Default Arguemnts

위에 설명한, 기본 값 지정에 대한 문제이다. 나처럼 풀면 이렇게 된다.

 

fun foo(name: String, number: Int, toUpperCase: Boolean) =
(if (toUpperCase) name.toUpperCase() else name) + number


fun foo(name: String, number: Int) = foo(name, number, false)

fun foo(name: String) = foo(name, 42)

fun foo(name: String, toUpperCase: Boolean) = foo(name, 42, toUpperCase)

 

fun useFoo() = listOf(
foo("a"),
foo("b", number = 1),
foo("c", toUpperCase = true),
foo(name = "d", number = 2, toUpperCase = true)
)

하지만 코틀린은 "기본 값을 지정" 할 수 있다.

다음과 같이 간단히 작성 할 수 있다.

 

fun foo(name: String, number: Int = 42, toUpperCase: Boolean = false) =
(if (toUpperCase) name.toUpperCase() else name) + number


fun useFoo() = listOf(
foo("a"),
foo("b", number = 1),
foo("c", toUpperCase = true),
foo(name = "d", number = 2, toUpperCase = true)
)

 

1.5 Lambdas

람다는 자바에서도 8 버전에서부터 지원하는 것으로 알고 있다.

코틀린 또한 당연히 람다를 지원한다.

 

함수를 파라미터로 받는 함수를, Higher order Function이라고 한다.

이런 함수에, 파라미터를 넘겨줄 때 람다를 쓰면 아주 깨끗한 코드를 만들 수 있다. (사람마다 코드의 미적 기준은 다를 수 있다.)

 

아래가 그 예시이다.

 

// Lambdas are code blocks enclosed in curly braces.
items.fold(0, { 
    // When a lambda has parameters, they go first, followed by '->'
    acc: Int, i: Int -> 
        print("acc = $acc, i = $i, ") 
    val result = acc + i
    println("result = $result")
    // The last expression in a lambda is considered the return value:
    result
})

 

 

함수 타입은 다음과 같이 나타낸다.

(R, T) -> R

 

코틀린은 변수를 쓸 때  var a: Int = 1  이런 식으로 쓸 수 있다. 

함수 타입이 (R, T) -> R 과 같은 방식이란 말은

 

var sampleFunction: (Int, Int) -> String = {
a: Int, b: Int -> "the result is $a + $b"
}

print(sampleFunction(1, 2))

결과: the result is 3

 

요런 식으로 쓸 수 있다는 말이다.

 

코틀린은 특이한 문법이 있다.

가장 마지막에 들어가는 "함수 인자" 는 parenthesis 밖으로 뺄 수 있다. (paraenthesis = ( or ) )

 

이게 무슨 개소린가 싶기도 한데...

 

fun higherOrderFunctionDefault(a: Int, b: Int, f: (Int, Int) -> Int): Int {
return f(a, b)
}

var result = higherOrderFunctionDefault(1,2, {a: Int, b: Int -> a + b})

print(result) -> 결과는 3이 나온다.

 

위와 같은 경우에.

 

var result = higherOrderFunctionDefault(1,2, {a: Int, b: Int -> a + b})

이 부분을

 

var result = higherOrderFunctionDefault(1,2){a: Int, b: Int -> a + b}

 

이렇게 쓸 수 있다는 말이다. 심지어 IntelliJ Edu 에서는 뒷 부분을 더 선호한다. ??? 

 

1.6 Strings

이건 그냥 답 봤다. 도저히 못 찾겠다.

String Template 에 관련된 문제인데... Docs 링크가 걸려있긴 하지만, 전혀 몰랐던 Template 적용 방식이 있었다.

자바 때부터 전해내려온 것인지, Kotlin에만 있는 것인지조차 잘 모르겠다. 이 부분은 좀 약하다.

 

1.7 Data Classes

class 앞에 data 를 붙이면, lomobk 의 @Data 와 비슷한 작동을 한다.

 

equals/hashCode, toString

 

함수를 자동으로 만들어 준다.

 

문제 자체는 간단하지만, 여기서 Kotlin의 클래스 개념을 잡고 넘어가야 한다.

 

오른쪽에 있는 링크를 따라가 차분히 읽어보도록 하자.

많은 것들을 다 적을 순 없고 간단히 특이한 점만 정리해 놓겠다.

 

1. 코틀린의 클래스 안의 필드들은, 반드시 초기화 돼야 한다.

2. main counstructor  라는 놈이 있다.

3. 일단 상속되는 놈이 먼저 생성되는건 자바와 똑같다. 따라서 주의할 점도 똑 같다.

4. 클래스 안에서의 문(Statement) 들은 무조건 순서대로 시작된다. 단 constructor는 예외 케이스가 있다.

   main constructor 가 있다면, 클래스 안쪽에 선언하는 놈들은 다 secondary constructor 인데,

   constructor keyword 를 이용해서 생성자를 추가할 수 있다. 이 때 반드시, main constructor을 this(name) 이런 식으로 호출해 줘야한

   다... 

ex)

class Constructors(var a: Int = 3) {
	constructor(i: Int, b: Int): this(i) {
  		println("Constructor")
	}
	init {
  		println("Init block")
	}
}

따라서 위와 같은 경우 init 이 먼저 시작된다. secondary constructor 보다는 init 이 우선시 된다.

main constructor 가 없다? 없을 수는 없다. 사실 암시적으로 갖고 있는 것이다. 마치 자바의 기본 생성자가 있듯이... 만약 main constructor 가 없다면, 암시적으로 호출하고 있다고 생각해야 한다.

 

그렇다면 순서대로라는 것은 무슨 의미인가?

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints ${name}")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

위와 같은 경우 반드시 순서대로 시작된다.  (위의 also 는 kotlin 의 확장 함수 중 하나이다. 자기 자신을 매개변수로 넘기고, 자기 자신을 return 한다.

val person: Person = getPerson().also {
	print(it.name)
	print(it.age)
}

마지막엔 자동으로 자기 자신을 return 한다.

 

5. main constructor 에는 연산을 넣을 수 없다. 따라서 연산을 위해서는 클래스 안에 init 을 사용하도록 해라.

6. class 는 클래스 : 부모클래스() 와 같이 상속. interface  는 클래스: 언터페이스 와 같이 상속한다.

7. 상속 하려면 open 키워드를 붙여야 한다.

 

다른게 무지 많다. 자세히 알아보지도 않고 대충 정리만 해놨다. 무엇보다 1번이 가장 애매한데... 초기화 안하면 컴파일러에서 빽빽돼서 저리 적어 놓았다.

 

1.8 Nullable Type

꽤나 중요한 문제이다.

fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
){
    val email = client?.personalInfo?.email
    if (email != null && message != null) {
        mailer.sendMessage(email, message)
    }
}

위가 정답이다. 깔끔하고 멋있다. kotlin 의 ? 의 힘이다.

자료형에 ? 가 붙어있는 것을 볼 수 있는데, null 이 들어갈 수도 있는 자료형을 나타낸다.

인스턴스에 ? 를 붙인뒤, 인스턴스의 자료 혹은 함수에 접근하려고 하면, null 을 자동으로 체크해준다.

만약 접근하려는 놈이 null 일 경우 그냥 null 을 반환한다. 그래서 마지막에 email != null 을 체크하는 것이다.

 

처음에 if 문을 하나만 써서 해결하라는 문구를 보고 나는 다음과 같이 문제를 해결했다.

fun sendMessageToClient(
        client: Client?, message: String?, mailer: Mailer
){
    if(client != null
            && message != null
            && mailer != null
            && client.personalInfo != null
            && client.personalInfo.email != null)
        mailer.sendMessage(client.personalInfo.email!!, message!!)
}

 굳이 이 흉한 코드를 올려놓은 이유는, !! 또한 키워드 중 하나이기 때문이다. ? 자료형의 변수에, !! 를 뒤에 붙여주면.

"이 값은 null 일리가 없다!" 라는 것을 의미한다. 따라서 String? 자료형의 변수는 String 으로 변해서 파라미터로 전달되는 효과가 있다.

 

1.9 smart casts

 

제목 그대로 "똑똑한 형변환" 을 의미한다. 일단 kotlin 에서는 if 문과 when 문을 사용해서 변수에 값을 할당할 수 있다는 것을 알고 넘어가자.

var a = 3;

var b = if(a == 3) 4 else 5 

이런 식으로 쓸 수 있다는 말이다. (많이 신기함..)

 

위에서는 If문과 When 문이라고 했지만.. Kotlin 에서의 If 는 "Expression" 이다.

이게 뭔 의미냐면, 반환형이 있다는 말이다.

If 표현의 마지막 문장은 자동으로 "반환 값" 이 된다.

 

따라서 Kotlin 에는 ? a : b 표현이 없다. If 로 충분하기 때문이다.

 

when 은 Java에서의 Switch 랑 비슷한데 여러모로 다른 점이 있다. 

fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> expr.value
            is Sum -> eval(expr.left) + eval(expr.right)
            else -> throw IllegalArgumentException("Unknown expression")
        }

위를 보면 알 수 있듯이, when 은 is 로 타입을 확인 할 수 있다. 자바로 따지면 instance of 같은 느낌이다.

왜 "똑똑한 형변환" 일까?

위에서 Expr 이 인터페이스라고 하자. 인터페이스를 구현한 클래스 A : Num , B : Sum 이 있다.

그럼 eval 함수에는 A 도, B 도 들어갈 수 있겠지? 

 

이 때 when 의 is 로 타입을 구분해서, 사용할 수 있다는 말이다.

 

잘 보면 expr.value, expr.left expr.right 라고 저녛 다른 것들을 사용 하는 것을 볼 수 있다.

 

interface 가 when 절의 is 를 통과했을 때, "자동으로" is 에서 비교한 타입으로 형변환 해서 넘어간다.

따라서 is Num 을 통과한 녀석은 Num 자료형으로 자동으로 변경돼서 들어간다.

똑똑하다는 말이다.

 

when의 is 는 타입을 비교할 때 쓴다, 보통은 왼쪽에 "조건식" 이 들어간다.

 

when (num) {

  1 -> "하나"

 2 -> "둘"

else -> "둘 초과"

}

이런 식으로 사용할 수 있다.

 

만약 when 에 아무런 인자도 넘어가지 않는다면, 그냥 "순수한 조건식" 만을 이용해서 사용할 수도 있다.

 

var a = 3

 

when {

  a == 3 -> "a는 3이 맞어"

  else -> "a 는 3이 아니여"

}

이런 식으로 말이다.

물론 위와 같이 쓸 필요는 없다. 위와 같으 2개의 분기로 나눠 질때는 if를 쓰면 된다.

 

3가지 이상의 분기로 나눠질 때 when을 사용하도록 하자.

 

1.9 Extension Function

 

확장 함수를 의미한다. 클래스의 확장 함수를 부여 할 수 있다.

그냥 클래스 안에다가 함수 만드는 것은 확장 함수가 아니다.

 

1.10 Object Expression

코틀린에서는 익명 클래스를 어떻게 사용할 수 있을까?

 

object: 인터페이스{

 override fun 함수이름() {}

}

    Collections.sort(arrayList, object: java.util.Comparator<Int> {
        override fun compare(o1: Int?, o2: Int?): Int {
            if(o1!! > o2!!) return -1 else if(o1 < o2) return 1 else return 0
        }
    })

 

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

 

Object Expressions, Object Declarations and Companion Objects - Kotlin Programming Language

 

kotlinlang.org

위의 object 표현식을 활용 하도록 하자.

주의 해야할 점은, 이 anonymous object 의 scope 이다.

anonymous object는 private이나 local 에서만 사용 가능하다.

 

public 으로 노출되면, 이 object는 순식간에 Any? 타입으로 바뀌어 버린다.

(Kotlin 에서의 Any 는 Java에서의 Object와 비슷한 맥락이지만. 절대 같지는 않다.)

 

class C {
    // Private function, so the return type is the anonymous object type
    private fun foo() = object {
        val x: String = "x"
    }

    // Public function, so the return type is Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // Works
        val x2 = publicFoo().x  // ERROR: Unresolved reference 'x'
    }
}

 

1.11 SAM Conversion

 

SAM Conversions

Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be automatically converted into implementations of Java interfaces with a single non-default method

 

1.12 Extension On Collection

 

문제 자체는 아주 간단하다. 

 

제목 그대로 Collection을 어떻게 확장해서 사용하고 있는지를 알려준다.

 

차트를 보면 3단원에 제대로 Collection을 다룰 예정인듯 하니 기다리도록 하자.

 

 

 

 


 

이렇게 1단원을 끝냈다.

굳이 정리할 필요는 없겠지만, 기본 문법이니 만큼 적어두는 것이 좋다고 생각했다.

 

이 포스트의 내용 만으로는 완벽히 Kotlin을 이해하기 힘들다.

글을 쓰고 있는 사람부터가 이해하고 쓰는게 아니고, 이해하기 위해, 혹은 이해하고 나서 훗날 기억하기 위해 적고 있기  때문이다.

 

화이팅 하자.

블로그 이미지

맛간망고소바

,