Uknow's Lab.
article thumbnail

 

 

익명 함수 (Anonymous Functions)

익명 함수란, 이름처럼 익명, 즉 이름을 가지지 않는 함수를 의미합니다.

 

// 익명함수
val sum = fun(x: Int, y: Int): Int {
    return x + y
}

fun main() {
    println(sum(1, 2))
}

// 출력
>>> 3

 

익명함수는 위와 같이 이름없이 정의되는 함수입니다.

앞서 (1)편에서 언급했듯이, 함수는 일급객체이기 때문에 변수에 할당이 가능합니다.

자바스크립트에서 많이 본 형태이죠?

저는 JS를 별로 안다뤄본 탓에 익숙해지는데 조금 걸렸습니다.

 

 

fun main() {
    val testP2 = ::testPrintln
    testP2()
}

fun testPrintln() {
    println("Hello World!")
}

 

또한, 미리 정의해놓은 함수를 :: 키워드를 사용해 변수에 할당할 수도 있습니다.

 

 

람다식 (Lambda Expression)

 

// 람다식
val sum = { x: Int, y: Int -> x + y }

fun main() {
    val result = sum(1, 2)
    println(result)
}

// 출력
>>> 3

 

람다식을 사용해 더 간단하게 표현할 수 있습니다.

위 람다식은 val sum = { 매개변수 : 타입, 매개변수2: 타입 -> 반환값 } 으로 표현하였습니다.

 

 

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
val sum = { x: Int, y: Int -> x + y } // 타입 추론을 이용해 선언부의 타입 생략 가능
val sum: (Int, Int) -> Int = { x, y -> x + y } // 타입 추론을 사용해 매개변수의 타입 생략 가능

 

람다식은 첫 번째 식이 가장 기본적인 상태이며

매개변수 부분에 타입이 명시되어 있다면 선언부를 생략,

선언부에 타입이 명시되어 있다면 매개변수 타입을 생략할 수 있습니다.

 

저는 두 번째 형태를 가장 즐겨 사용합니다.

 

 

인자가 하나일 땐 it 키워드로 암시적으로 받을 수 있다

 

fun main() {
    val plus: (a: Int) -> Int = { a -> a + 1 }
    println(plus(1))
}

// 출력
2


==================================================


fun main() {
    val plus: (Int) -> Int = { it + 1 }
    println(plus(1))
}

// 출력
2

 

두 코드의 plus는 모두 받은 인자를 +1 하여 return 해주는 람다식입니다.

매개변수가 하나일 땐 it 키워드를 사용해 암시적으로 받을 수 있습니다.

 

 

함수를 파라미터로 전달

 

// 함수를 파라미터로 전달
fun function(a: Int, b: Int, func: (Int, Int) -> Int): Int {
    return func(a, b)
}

fun main() {
    val sumFunc = { a: Int, b: Int -> a + b } // 더하는 람다식
    val multiFunc = { a: Int, b: Int -> a * b } // 곱하는 람다식

    val sumResult = function(10, 20, sumFunc)
    val multiResult = function(10, 20, multiFunc)
    val subResult = function(10, 20, { a, b -> a - b }) // 빼는 람다식

    println(sumResult)
    println(multiResult)
    println(subResult)
}

// 출력
>>> 30
200
-10

 

function 함수는 a, b와 (Int, Int) -> Int 형식의 람다함수를 인자로 받습니다.

매개변수가 Int 2개, return이 Int인 형식의 람다식이면 다 받을 수 있다는 의미이죠.

그리고 a, b와 람다함수를 갖고 로직을 수행합니다.

 

fun main()에서

sumFunc는 두 인자를 더하는 람다식,

multiFunc는 두 인자를 곱하는 람다식입니다.

 

이와 같은 람다식은 마치 값을 변수에 할당하듯 함수를 변수에 할당한 후

변수를 매개변수로 넘겨주듯이 매개변수로써 함수를 넘겨줄 수 있습니다.

 

물론, 변수에 할당하지 않은 채 subResult와 같이 바로 람다식을 넣어줄 수도 있습니다.

 

 

printIf 구현하기

// lambda function
fun String.printIf(func: (Char) -> Boolean) {
    this.forEach {
        if (func(it)) print(it)
    }
}

fun main() {
    val str = "Hello World Koltin"
    str.printIf { it.isUpperCase() }
}

// 출력
>>> HWK

 

filter { }, countIf { }, sumIf { } 등 추후 컬렉션 프레임워크 파트에 나올 이들도

코틀린 람다식에 기반을 두고 있습니다.

 

저는 앞서 나온 확장함수와 람다식을 사용해

조건에 맞는 문자열을 뽑아 출력하는 printIf를 구현해봤습니다.

 

꽤 간단히 구현할 수 있었는데요.

확장함수 편에서 배운 String.(메소드명)을 통해, String의 메소드를 추가해줬고,

인자로써 func: (Char) -> Boolean 형식의 람다식을 받을 수 있도록 했습니다.

 

그리고 String 내 문자열을 하나씩 돌리며 (this.forEach)

만약 매개변수로 밭은 함수에 인자로 현재 문자을 넣었는데 (func(it))

이게 true를 반환한다면 if(func(it))

출력한다 print(it) 입니다.

 

 

forEach 함수는 for문 편에서 한 번 나온 녀석이였는데,

각 원소를 하나씩 순회하는 반복문입니다.

 

 

fun String.printIf(func: (Char) -> Boolean) {
    // val str = "Hello World Kotlin"
    // str.printIf 와 같이 사용하면 str를 this로 받을 수 있음.
    
    this.forEach {
        // str내 문자 하나하나를 it으로 받음.
        // func(it)는 func의 인자로 it를 넣어서 실행한 결과를 받음.
        // str.printIf { it.isUpperCase() } 라고 사용하면
        // func(it)는 it.isUpperCase()를 실행한 결과를 받음.
        if (func(it)) print(it)
    }
}

 

주석을 달아 설명을 보태봤습니다.

 

 

함수형 프로그래밍편 마침

지금까지 함수형 프로그래밍에 관한 소개와 간단한 실습을 해봤습니다.

 

으음... 함수형 프로그래밍이 뭔지, 어떻게 구현하는지는 대강 알겠는데

어떻게 활용해야 하는지는 아직 잘 모르겠습니다.

 

나중에 함수형 프로그래밍을 잘 활용하게 된다면,

함수형 프로그래밍에 관한 글을 하나 더 올려야겠네요.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.