본문 바로가기

프로그래밍/Kotlin

[Kotlin 요약 정리] 11. 고차 함수와 인라인 함수

11. 고차 함수와 인라인 함수

1) 고차함수

- 매개변수로 함수를 전달받거나 함수를 반환하는 함수

- 매개변수가 함수 1개일 경우 괄호() 를 생략하고 예약어 형태로 사용 가능

 

fun function1(func: (Int) -> Int, num: Int) = func(num)

fun function2(func: (Int) -> Int) = func(10)

fun pr(func: (Any) -> Any) = println(func(10))



fun main() {

   val a = function1({ it * 10 }, 10)



   val b = function2( { it * 10} )

   val c = function2 { it * 10}



   println("a: $a / b: $b / c: $c")



   pr { 10 * 10 }

}

// 결과

a: 100 / b: 100 / c: 100

100

 

- 매개변수가 여러개일 경우에도 마지막 인수는 괄호 () 밖에서 사용 가능

- 일반 함수에서와 같이 인수가 생략된 경우에 사용할 기본값 지정 가능

 

typealias SomeType = (Int, String) -> Boolean



fun funcTest(argA: Int, argB: String, argC: SomeType = { i, j -> i.toString() == j }) {

   println("argA: $argA /argB: $argB / argC: ${argC(argA, argB)}")

}



fun main() {

   funcTest(1, "1")

   funcTest(1, "1", { i, j -> i.toString() != j })

   funcTest(3, "5") { i, j -> i.toString() != j }

}

// 결과

argA: 1 /argB: 1 / argC: true

argA: 1 /argB: 1 / argC: false

argA: 3 /argB: 5 / argC: true

 

2) 고차 함수에서의 함수 참조

- 고차 함수 이용시 함수 참조 연산자 :: 이용 가능

 

fun func1(argFun: (String) -> String) {

   val result = argFun("text")

   println(result)

}



fun func2(str: String): String{

   println(str)

   return str.toUpperCase()

}



fun main() {

   func1(::func2)

}

// 결과

text

TEXT



3) 익명 함수

- 람다 함수와 달리 return 예약어 사용이 가능하며 반환 타입을 명시적으로 선언 가능

- 주로 고차 함수의 매개변수나 반환값에서 타입을 명시적으로 선언하려고 할 때 이용

 

val aFunc = fun(name: String): String{

   return "Hi $name"

}



fun main() {

   println(aFunc("Nick"))

}

// 결과

Hi Nick



4) run() 함수

- run(): 람다 함수를 실행해서 값을 얻을 목적 혹은 객체의 멤버에 접근하기 위해 사용

 

fun main() {

   val num = run {

       println("20")

       20

   }

   println(num)

}

// 결과

20

20

 

class Member(){

   var name: String = ""

   var age: Int = 0

   fun say()= println("Hello $name")

}



fun main() {

   val member = Member()

   val runrun = member.run {

       name = "Nick"

       age = 10

       say()

       "My age: $age"

   }



   println(runrun)

}

// 결과

Hello Nick

My age: 10



5) apply() 함수

- run() 함수와 사용 목적은 같으나 run() 함수는 함수의 반환값을 반환하고 apply() 함수는 객체 자체를 반환

 

data class Member(var name: String, var age: Int)



fun main() {

   val member = Member("Nick", 10)

   val runrun = member.apply {

       name = "John"

       age = 20

   }



   println(runrun.toString())

}

// 결과

Member(name=John, age=20)



6) let() 함수

- 전달받은 람다 함수에 매개변수를 전달하고 반환값을 전달받는 함수

- 객체 선언을 줄이려는 목적으로 사용

 

data class Human constructor(var name: String, var age: Int)



fun printHuman(human: Human):Int {

   println("${human.name} / ${human.age}")

   return human.age

}



fun main() {

   val age = Human("Nick", 10).let { printHuman(it) }

   println(age)

}



// 결과

Nick / 10

10

 

 

7) with() 함수

- 한 객체의 멤버에 반복해서 접근할 때 객체명 명시 없이 멤버에 접근 가능

 

fun main() {

   val member = Member("Nick", 10)

   with(member){

       name = "John"

       age = 20

   }

   println(member.toString())

}

// 결과

Member(name=John, age=20)



8) inline 함수와 noinline

- inline 예약어를 사용해서 선언한 함수

- 컴파일 단계에서 함수를 선언하지 않고 정적인 코드로 포함된다.

- 일반 함수에서 사용시 큰 이점이 없으며 고차 함수에서 사용시 성능 문제를 개선할 수 있다.

- 인라인 함수 내의 람다 함수에서 return을 사용할 수 있다.(crossinline 예약어 사용시 return 사용 불가)

 

- noinline: inline이 선언된 함수에서 noinline 예약어를 이용해서 inline에 포함시키지 않을 함수 매개변수를 명시적으로 선언할 수 있다.

 

9) 라벨

- 람다 함수에 라벨을 지정 후 해당 라벨만 return 가능

- 라벨을 선언하지 않아도 함수명으로 된 라벨이 자동 추가

 

fun labelTest(){

   println("labelTest Start")

   val array = intArrayOf(1,2,3,4,5)

   array.forEach {

       if(it == 3) return

       println(it)

   }

   println("labelTest Finish")

}



fun main() {

   labelTest()

}

// 결과

labelTest Start

1

2

 

fun labelTest(){

   println("labelTest Start")

   val array = intArrayOf(1,2,3,4,5)

   array.forEach foreach@{

       if(it == 3) return@foreach

       println(it)

   }

   println("labelTest Finish")

}



fun main() {

   labelTest()

}

// 결과

labelTest Start

1

2

4

5

labelTest Finish



10) 클로저

- 함수가 호출될 때 발생하는 데이터를 함수 호출이 끝난 후에도 그대로 유지해서 사용하는 기법

 

fun closureTest(): () -> String {

   val data = "Data"

   return { data }

}



fun main() {

   val a = closureTest()

   println(a())

}

// 결과

Data