References: Do it! 코틀린 프로그래밍

코틀린에서의 확장함수와 중위함수에 대해 알아봅니다.

 

 

1. 확장함수.

 

클래스에는 다양한 함수가 정의되어 있습니다. 이미 정의되어 있는 이런 함수들을 클래스의 멤버 메서드라고 합니다.

만약 자기가 원하는 기능을 가진 함수를 클래스에 추가시키고 싶으면 어떻게 할까요?

코틀린에선 이러한 기능을 제공해주며 이를 확장함수라고 합니다.

 

String클래스에 확장함수를 구현하면 String클래스를 쓸 때 사용할 수 있습니다.

만약 Any클래스에 확장함수를 구현해둔다면 모든 클래스에서 사용할 수도 있습니다.

 

String 변수 두개중에 더 긴값을 출력하는 함수를 사용하고자 합니다.

String클래스의 멤버메서드엔 이러한 기능흘 하는 메서드가 없어 새로 확장함수를 추가하려고 합니다.

다음 예시를 확인해봅시다.

fun String.getLongerString(target: String): String = if(this.length > target.length) this else target
fun main(){
    val s1 = "Hello kotlin!"
    val s2 = "Hello!"
    println(s1.getLongerString(s2));
}

String클래스에 getLongerString 확장함수를 추가했습니다. 실행 결과는 다음과 같습니다.

이런 확장함수를 사용하면 기존 클래스의 선언을 수정하지 않아도 쉽게 기능을 확장할 수 있습니다.

 

만약 이미 동일한 멤버함수나 메서드가 존재한다면 항상 확장함수보다 멤버 메서드가 우선적으로 호출됩니다.

 

 

2. 중위함수.

 

중위 표현법은 변수와 변수사이에 함수를 넣어 연산자 처럼 사용하는 것 입니다.

예를들어 multi라는 두 수를 곱하는 함수를 중위 함수로 만들었다면

a multi b

처럼 사용할 수 있는 함수가 중위함수입니다.

 

다음 예시로 확인해 봅시다.

infix fun Int.multi(a: Int): Int = this * a
fun main() {
    var result: Int = 2 multi 4
    println(result)
}

infix 키워드를 이용해 중위 함수를 선언하고 사용했습니다.

일반적인 함수라면 2.multi(4) 와 같은 방식으로 사용할겁니다.

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 17. 조건문  (0) 2019.08.23
[Kotlin] 16. 꼬리 재귀 함수  (0) 2019.08.23
[Kotlin] 14. 인라인 함수  (0) 2019.08.23
[Kotlin] 13. 익명함수  (0) 2019.08.23
[Kotlin] 12. 함수 호출 방법  (0) 2019.08.22

References: Do it! 코틀린 프로그래밍

코틀린에서의 인라인 함수에 대해 알아봅니다.

 

 

1. 인라인함수란?

 

일반 함수가 호출되면 분기가 일어납니다. 따라서 내부적으로 기존 작업 내용을 저장했다가 다시 돌아올 때 복구하는 작업이 필요하며 이러한 작업에 CPU와 메모리에 비용이 발생합니다.

 

인라인 함수는 일반 함수와 달리 인라인 함수의 모든 내용을 함수가 호출되는 곳에 복사합니다.

예를들면

 

fun main(...) {
    ...
    sum()
    ...
    sum()
}
fun sum(){
    //Sum process
}

 

위와 같은 일반함수는 sum()이 호출될 때마다 분기가 일어나 총 2번의 분기가 발생합니다.

만약 sum()이 아래와 같이 인라인 함수로 선언되어 있다면 

inline fun sum(){
    //Sum process
}

 

함수가 실행될 때 sum()함수로 이동되는게 아닌 함수 내용이 복사되어 다음과 같이 수행됩니다.

 

fun main(...) {
    ...
    //Sum process
    ...
    //Sum process
}

 

 

2. 인라인 함수의 제한.

 

인라인 함수의 경우 모든 함수 내용을 복사해 넣기 때문에 함수의 코드가 길면 성능 문제가 발생할 수 있습니다.

다음 예시를 통해 인라인 함수를 제한하는 법을 알아보겠습니다.

 

inline fun sum(out1: ()->Unit, out2: ()->Unit)

 

위의 함수가 인라인으로 실행되면 내부의 두 람다함수도 인라인으로 들어가게됩니다. 

이런함수를 여러번 호출하게되면 코드의 양이 많아지는 문제가 발생합니다.

이런 문제를 해결하기 위해 일부 람다식은 인라인으로 실행되지 않게 하기 위해 noinline 키워드를 사용합니다.

 

inline fun sum(out1: ()->Unit, noinline out2: ()->Unit)

 

 

3. 비지역 반환

 

코틀린에서 익명함수를 종료하기 위해서 return을 사용할 수 있습니다.

그럼 인라인함수에서 사용한 람다식은 어떻게 빠져나올수 있을까요?

인라인 함수내부의 람다식에서는 return문을 사용할 수 있습니다.

다음 예시를 살펴봅시다.

 

inline fun inlineFun(a: Int, out: (Int)->Unit) {
    println("Before calling out()")
    out(a)
    println("After calling out()")
}
fun main(){
    inlineFun(1) {
        println("First call $it")
        return
    }
}

 

위의 예시에서 out(a)는 인라인되어 대체됩니다. 따라서 return을 포함하게 됩니다. 

이로 인해 out(a)에서 return이 포함되버려 println("After calling out()")는 실행되지 않게 됩니다.

이렇게 람다함수에서 return을 만났지만 의도하지 않은 바깥함수인 inlineFun()가 반환 처리되는 것을 비지역 반환이라고 합니다.

 

이런 의도치 않은 비지역 반환을 금지시키기 위해 다음과 같이 코드를 수정합니다.

 

inline fun inlineFun(a: Int, crossinline out: (Int)->Unit) {
    println("Before calling out()")
    nestedFun{ out(a) }
    println("After calling out()")
}
fun nestedFun(body: ()->Unit){
    body()
}
fun main(){
    inlineFun(1) {
        println("First call $it")
        //crossinline에 의해 더이상 return을 사용할 수 없습니다.
    }
}

 

crossinline 은 비지역 반환을 금지해야하는 람다식에 사용됩니다. 

결과를 출력시켜보면 정상적으로 After calling out()이 출력되는걸 확인할 수 있습니다.

 

 

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 16. 꼬리 재귀 함수  (0) 2019.08.23
[Kotlin] 15. 확장함수와 중위함수  (0) 2019.08.23
[Kotlin] 13. 익명함수  (0) 2019.08.23
[Kotlin] 12. 함수 호출 방법  (0) 2019.08.22
[Kotlin] 11. 람다식  (0) 2019.08.22

References: Do it! 코틀린 프로그래밍

코틀린에서의 익명함수에 대해 알아봅니다.

 

1. 익명함수

 

익명함수(Anonymous Function)이란 일반함수지만 함수의 이름지 존재하지 않는 함수입니다.

익명함수의 예시는 다음과 같습니다.

fun(a: Int, b: Int): Int = a + b

위의 익명함수는 변수선언에 그대로 이용할 수 있습니다.

val add: (Int, Int) -> Int = fun(a, b) = a + b
//OR
val add = fun(a: Int, b: Int): Int = a + b

 

 

2. 익명함수를 사용하는 이유.

 

겉보기엔 익명함수는 람다식과 매우 유사해 보입니다.

실제로 익명함수 대신에 람다식을 사용해도 됩니다. 그러면 왜 익명함수를 사용할까요?

람다식에선 return, break, continue와 같은 제어문을 사용하기 어렵기 때문입니다.

함수내 조건에 따라 실행을 중단하고 리턴해야 하는 경우에는 익명함수를 사용하는게 좋습니다.

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 15. 확장함수와 중위함수  (0) 2019.08.23
[Kotlin] 14. 인라인 함수  (0) 2019.08.23
[Kotlin] 12. 함수 호출 방법  (0) 2019.08.22
[Kotlin] 11. 람다식  (0) 2019.08.22
[Kotlin] 10. 함수의 매개변수  (0) 2019.08.21

References: Do it! 코틀린 프로그래밍

코틀린에서의 함수 호출방법에 대해 알아봅니다.

 

 

1. 값에 의한 호출

 

값에 의한 호출로 람다식이 전달되는 경우 람다함수는 값으로 처리되어 바로 람다함수가 수행되며 그 후 결과 값을 전달합니다.

다음 예시를 통해 확인해 보겠습니다.

fun callByValue(b: Boolean): Boolean{
    println("Called callByValue function.")
    return b
}
val lambdaFunc: ()->Boolean = {
    println("Called lambdaFunc function")
    true
}
fun main() {
    val result = callByValue(lambdaFunc())
    println(result)
}

callByValue(lambdaFunc()) > 람다함수는 값으로 처리되어 즉시 수행됨. 결과값 true를 리턴.

callByValue(lambdaFunc()) > 람다함수가 실행된 결과값인 true를 인자로 함수가 실행됨.

 

위에 설명한 순서대로라면 결과값은 다음과 같이 출력됩니다.

 

 

2. 이름에 의한 호출

 

람다함수를 이름으로만 호출해보겠습니다.

코드를 다음과 같이 변경해줍니다.

fun callByName(b: ()->Boolean): Boolean{
    println("Called callByName function.")
    return b()
}
val lambdaFunc: ()->Boolean = {
    println("Called lambdaFunc function")
    true
}
fun main() {
    val result = callByName(lambdaFunc)
    println(result)
}

fun callByValue(b: ()->Boolean): Boolean > 람다식을 이름으로만 호출하기 위해 자료형을 람다식으로 변경해줍니다.

return b() > 람다식을 리턴합니다.

 

실행순서는 값에 의한 호출과 다릅니다.

A. callByValue(lambdaFunc) > 람다함수가 저장된 변수가 함수의 인자로 전달됩니다.

B. fun callByValue(b: ()->Boolean): Boolean > 인수를 받아온 함수가 실행됩니다.

C. return b() > 인수가 리턴됩니다.

D. val lambdaFunc: ()->Boolean > 리턴된 인수안에 담겨있는 람다함수가 실행됩니다.

E. true > 람다함수의 결과값인 true가 리턴됩니다.

 

위에 설명한 순서대로라면 결과값은 다음과 같게 출력됩니다.

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 14. 인라인 함수  (0) 2019.08.23
[Kotlin] 13. 익명함수  (0) 2019.08.23
[Kotlin] 11. 람다식  (0) 2019.08.22
[Kotlin] 10. 함수의 매개변수  (0) 2019.08.21
[Kotlin] 09. 함수의 선언과 간략화  (0) 2019.08.21

References: Do it! 코틀린 프로그래밍

코틀린에서의 람다식과 사용예시에 대해 알아봅니다.

 

 

1. 람다식

 

람다식은 람다 대수에서 유래했다고 합니다. 람다식의 예시는 다음과 같습니다.

{ x, y -> x + y }

예시를 보면 함수에 이름이 없고 화살표가 사용되었습니다. 

수학에서의 람다 대수는 이름없는 함수로 2개 이상의 입력을 하나의 값으로 단순화 한다는 개념입니다.

프로그래밍에서도 유사하게 1. 함수의 이름이 없으며 2. 여러 입력값을 하나로 리턴합니다.

 

 

2. 람다함수의 사용예시.

 

실제로 람다 함수는 다음과 같이 사용됩니다.

 

fun sumFun(sum: (Int, Int) -> Int, a: Int, b: Int): Int{
    return sum(a, b)
}

fun main(){
    println(sumFun( { x, y -> x + y }, 1, 2))
}

 

fun sumFun(sum: (Int, Int) -> Int, a: Int, b: Int): Int > 람다식으로 사용할 매개변수 이름.

fun sumFun(sum: (Int, Int) -> Int, a: Int, b: Int): Int > 자료형을 람다식으로 선언.

return sum(a, b) > 매개변수로 선언한 람다식을 사용

sumFun( { x, y -> x + y }, 1, 2) 인자로 람다식을 전달

 

람다식을 변수에 저장하여 사용할 수도 있습니다.

fun main(){
    var result: Int
    val multi = { a: Int, b: Int -> a * b }
    result = mulit(2,4)
}

multi를 보면 변수에 람다식을 저장해 함수처럼 사용할 수 있는것을 알 수 있습니다.

 

val multi = { a: Int, b: Int -> a * b }

 

위 식을 좀 더 자세히 써보겠습니다.

 

val multi: (Int, Int) -> Int = { a: Int, b: Int -> a * b }

 

람다식 자료형을 모두 표현한 식입니다.

이 식은 다시 다음과 같이 나타낼 수 있습니다.

 

val multi: (Int, Int) -> Int = { a, b -> a * b }

 

첫 예시는 변수선언의 람다식 자료형을 생략한 표현이고 위의 예시는 람다식내의 매개변수 자료형을 생략한 표현입니다.

물론 두개 다 생략하면 코틀린은 더이상 자료형을 추론할 수 없어 오류가 발생합니다.

 

매개변수가 없는 람다식 표현의 경우 다음과 같이 작성하면 됩니다.

 

val printHello: () -> Unit = { println("Hello") } //OR val printHello = { println("Hello") }

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 13. 익명함수  (0) 2019.08.23
[Kotlin] 12. 함수 호출 방법  (0) 2019.08.22
[Kotlin] 10. 함수의 매개변수  (0) 2019.08.21
[Kotlin] 09. 함수의 선언과 간략화  (0) 2019.08.21
[Kotlin] 08. 스마트 캐스트  (0) 2019.08.21

References: Do it! 코틀린 프로그래밍

함수의 매개변수에 대해 알아봅니다.

 

 

1. 매개변수의 기본값 설정하기.

 

함수 매개변수의 기본값은 다음과 같이 설정합니다.

 

fun addUser(id: String, email: string = "Default"){
    ...
}

 

이후 기본값이 있는 매개변수는 함수 호출시 인자를 넘겨주지 않아도 됩니다.

addUser("smoh", "seungmuk92@gmail.com") //OK
addUser("smoh") //OK

 

 

2. 매개변수를 이름과 함께 호출하기.

 

만약 함수의 매개변수가 많아지면 어떤 인자를 어떤 매개변수에 전달해야하는지 헷갈릴 수 있습니다.

그럴때를 위해 코틀린은 매개변수의 이름과 함께 인자를 전달할 수 있는 방법을 제공합니다.

fun connect(host: String = "localhost", port: int = 1521, user: String = "Default", password: String){
    ...
}

위와 같이 매개변수가 많은 함수가 있을 때 다음과 같이 호출할 수 있습니다.

connect(host = "127.0.0.1", password = "12345") //OK, 나머지 값은 기본값 사용.
connect(password = "12345") //OK, 나머지 값은 기본값 사용.

단, 기본값이 지정되지않은 password는 항상 전달해야 합니다.

 

 

3. 매개변수가 고정되지 않은 함수.

 

매개변수의 갯수가 고정되지 않은 함수는 가변인자(Variable Argument)를 사용하면 만들 수 있습니다.

가변인자를 이용한 함수는 다음과 같이 정의합니다.

fun printArgs(vararg words: String){
    for(word in words) { print("$word ") }
    print("\n")
}

이후 해당 함수는 다음과 같이 호출 할 수 있습니다.

printArgs("Hello", "World", "!") //OK
printArgs("Hello", "World", "&", "Hello", "Kotlin") //OK

 

 

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 12. 함수 호출 방법  (0) 2019.08.22
[Kotlin] 11. 람다식  (0) 2019.08.22
[Kotlin] 09. 함수의 선언과 간략화  (0) 2019.08.21
[Kotlin] 08. 스마트 캐스트  (0) 2019.08.21
[Kotlin] 07. Null 허용 및 NPE 검사  (0) 2019.08.21

References: Do it! 코틀린 프로그래밍

함수의 선언방법과 간략히 하는 방법에 대해서 알아봅니다.

 

 

1. 함수의 선언

 

함수는 다음과 같이 선언합니다.

fun sum(a: Int, b: Int): Int {
    var result = a + b;
    return result;
}

fun sum(a: Int, b: Int): Int > 함수의 이름을 의미합니다.

fun sum(a: Int, b: Int): Int > 함수의 매개변수를 의미합니다.

fun sum(a: Int, b: Int): Int > 함수의 반환 타입을 의미합니다.

 

만약 반환형이 없는 만들고 싶으면 fun voidFunc(): Unit 처럼 "Unit"를 사용하거나 자료형을 생략하면 됩니다.

코틀린은 함수의 반환형이 없으면 자동으로 Unit로 추론합니다.

 

** void함수와 Unit를 반환하는 함수는 다릅니다.

** void함수는 아무것도 반환하지 않지만 Unit함수는 Unit 객체를 반환합니다.

 

 

2. 함수 간략화

 

코틀린에서 지원하는 함수를 간략하게 하는법을 알아봅니다.

 

위의 예시함수는 아래와 같이 간략하게 만들 수 있습니다.

fun sum(a: Int, b: Int): Int {
    return a + b;
}

다른 언어에서도 위와같은 방법으로 많이 사용합니다.

코틀린에선 중괄호 내의 코드가 한줄이면 중괄호와 return을 생략 할 수 있습니다.

fun sum(a: Int, b: Int): Int = a + b

여기서 우리가 만든 sum 함수는 Int + Int = Int이므로 함수의 반환형인 Int도 생략할 수 있습니다.

fun sum(a: Int, b: Int) = a + b

 

 

반응형

'Programming' 카테고리의 다른 글

[Kotlin] 11. 람다식  (0) 2019.08.22
[Kotlin] 10. 함수의 매개변수  (0) 2019.08.21
[Kotlin] 08. 스마트 캐스트  (0) 2019.08.21
[Kotlin] 07. Null 허용 및 NPE 검사  (0) 2019.08.21
[Kotlin] 06. 자료형 String  (0) 2019.08.21

References: Do it! 코틀린 프로그래밍

자료형의 스마트 캐스트와 Any및 as에 대해 알아봅니다.

 

 

1. 스마트 캐스트

 

스마트 캐스트란 어떤 값이 정수일수도 있고 실수일수도 있는 상황에서 컴파일러가 자동으로 형을 변환해주는 기능을 말합니다.

말한 예시대로 정수와 실수 즉 숫자형에 대한 스마트 캐스트가 적용되는 자료형은 Number가 있습니다.

var num: Number = 11.1

위의 코드에서 num은 스마트 캐스트에 의해 자동으로 Float형이 됩니다.

 

 

2. Any

 

자료형을 결정하지 않은채 변수를 선언하고 싶을땐 Any형을 사용하면 됩니다.

val value: Any
value = "Hello kotlin!"
if(value is String) { println(value) }

value를 선언 할 때 Any라는 타입으로 변수가 선언됩니다.

이후 "Hello kotlin!"이 할당된 후(아직 자료형은 Any로 남아있습니다) is를 통해 형을 검사할때 자동으로 String으로 스마트 캐스팅 되어 조건문을 수행하게 됩니다.

 

Any는 모든 자료형 클래스의 최상단에 위치합니다. 다시말하면 코틀린의 모든 클래스는 Any라는 슈퍼 클래스를 가집니다.

이로인해 Any를 사용한 자료형은 묵시적 변환에 의해 어떤 자료형으로든 변경될 수 있습니다. 따라서 아래와 같이 구분할 수도 있습니다.

fun checkArgType(input: Any)
    if(input is String) { println("input value is String") }
    if(input is Int) { println("input value is Int)}
}

 

 

3. as

 

as를 사용해 스마트 캐스트를 수행 할 수도 있습니다. 

단, as는 형변환이 가능하지 않으면 예외를 발생시킵니다.

val str2: String = str1 as String

위의 코드는 str1이 null이 아니면 String으로 형변환 되어 str2에 할당하는 코드입니다.

만약 str1이 null이면 형변환이 불가능하므로 예외를 발생합니다. 따라서 위의 코드는 다음과 같이 바꿔 수행하는게 더 안전합니다.

val str2: String? = str1 as? String
반응형

References: Do it! 코틀린 프로그래밍

Null을 허용하는 변수 설정과 NullPointerException(NPE)을 방지하는 법에 대해 알아봅니다

 

 

1. Null을 허용하는 변수 설정하기.

 

코틀린에서는 기본적으로 변수에 NULL값을 허용하지 않습니다.

위와 같이 String 타입 변수에 null을 넣으려고 하면 에러를 반환합니다.

 

직접 null을 할당하려면 다음과 같이 해야합니다.

1. 명시적으로 자료형을 선언해줘야 하며

2. NULL을 허용한다는 의미로 ? 를 자료형 뒤에 입력해줘야 합니다.

 

 

2. 세이프 콜

 

위의 예시에서 value의 길이를 구해봅시다.

세이프 콜 (?.)이나 non-null(!!.)만 허용한다는 에러를 확인할 수 있습니다.

 

세이프 콜이란 null이 할당되어 있을 가능성이 있는 변수를 검사하여 안전하게 호출하도록 도와주는 기법입니다.

이번엔 세이프콜을 적용하여 길이를 구해봅시다.

fun main() {
    var value:String? = "Hello kotlin"
    value = null;
    var length = value?.length
    println(length);
}

실행하면 결과가 어떻게 나오나요? 

세이프 콜은 변수를 검사 한후 값이 있으면 길이를, 값이 null이면 null을 출력합니다. 위의 코드를 실행하면 null이 출력될 것 입니다.

 

 

3. non-null 단정 기호.

 

이번엔 non-null 단정기호인 !!.을 사용해 봅시다.

코드를 아래와 같이 수정한 후 실행해봅니다.

fun main() {
    var value:String? = "Hello kotlin"
    value = null;
    var length = value!!.length
    println(length);
}

물론 컴파일러에서 에러를 보여주긴 합니다.

그러나 정상적으로 컴파일은 되고 실행하면 NPE가 발생합니다.

Exception in thread "main" kotlin.KotlinNullPointerException

 

 

4. 조건문을 활용한 변수 검사

 

기본적으로 조건문을 사용해 변수의 null 가능성을 검사할 수도 있습니다.

fun main() {
    var value:String? = "Hello kotlin"
    value = null;
    val length = if(value != null) value.length else -1
    println(length);
}

 

 

5. 세이프 콜과 엘비스(Elvis)를 사용한 변수 검사.

 

세이프 콜(?.)과 엘비스 연산자(?:)를 함께 사용하면 좀 더 안전하게 변수를 검사할 수 있습니다.

fun main() {
    var value:String? = "Hello kotlin"
    value = null;
    val length = value?.length ?: -1
    println(length);
}

결과값은 -1을 출력합니다.

 

"value?.length ?: -1"에 대해 알아봅시다.

세이프 콜인 value?.length는 위에서 살펴본 바와 같이 null을 리턴합니다.

엘비스 연산자는 좌측의 값이 null이면 우측의 값을 리턴하고, null이 아니면 좌측의 값을 그대로 리턴합니다.

따라서 null ?: -1이므로 -1을 리턴하게 됩니다.

 

 

반응형

References: Do it! 코틀린 프로그래밍

String 자료형에 대해 알아봅니다.

 

 

1. 문자열 자료형 선언과 저장 방식.

 

문자열을 다음과 같이 선언 합니다.

var str1: String = "Hello"
var str2 = "World"
var str3 = "Hello"

위와같이 문자열을 선언 하면 실제 메모리엔 다음과 같이 저장됩니다.

Heap: StringPool[ (A1:Hello), (A2:World) ]

Stack: Address[ (A1: str1), (A2: str2), (A1: str3) ]

실제 str1과 str3이 바라보는 곳은 A1입니다.

따라서 str1 == str3의 결과는 true를 반환합니다.

 

 

2. 문자열 출력하기

 

변수의 값을 문자열에 입력하기 위해 $ 기호를 사용할 수 있습니다.

다음 코드를 봅시다.

var value = 100
var str = "value is $value"

str 변수를 초기화 하고 value의 값을 사용합니다. 따라서 str은 "value is 100"으로 초기화 됩니다.

 

만약 변수를 그대로 사용하지 않고 계산 결과를 입력하고 싶으면 어떻게 해야할까요

표현식을 사용하면 가능합니다. 표현식은 중괄호({})를 통해 사용할 수 있습니다.

다음 코드를 확인해 봅시다.

var value = 100
var str1 = "value is $value"
var str2 = "value +10 is ${value +10}"

위의 코드에서 ${value +10}은 실제 value인 100에 10을 더한값. 즉 110이 할당됩니다.

따라서 str2는 "value +10 is 110"으로 초기화됩니다.

 

반응형

+ Recent posts