이름이 없는 함수
람다식도 일종의 익명함수이다. 하지만 람다식에서는 return, break, continue 등의 키워드 사용이 어렵다.
함수 선언 시 fun 앞에 inline을 붙인다
fun main() {
sum(1,2)
sum(3,4)
}
inline fun sum(x:Int,y:Int):Int{
return x+y
}
일반 함수는 호출하면 분기해서 함수를 실행하고 다시 돌아와야 한다.
인라인 함수는 호출하면 인라인 함수의 내용을 복사해서 가져오게 된다.
분기하지 않아도 되서 성능이 증가한다.
하지만 인라인 함수의 내용이 많고 여러번 호출한다면 같은 코드를 계속 복사해야 해서 비효율적이다.
코드에 중단점을 기록하고 debug를 누른 후 step into를 하나씩 누르며 프레임을 관찰해보면 inline함수를 사용할 때와 일반 함수를 사용할 때 차이점을 확인할 수 있다.
Tool -> Kotlin -> Show Kotlin ByteCode 메뉴에서 바이트코드로 들어간 후 Decompile을 눌러서 자바코드를 확인해보면 더 명확하게 알 수 있다.
inline 함수를 사용하면 노란색으로 경고가 생긴다.
inline 함수는 성능에 영향을 미친다. inline 함수는 매개변수로 함수를 갖는 함수에 사용하는 것이 가장 바람직하다.
fun main() {
sum(2,3,{a,b->a*b})
}
inline fun sum(x:Int,y:Int,op:(a:Int,b:Int)->Int):Int{
return op(x,y)
}
이렇게 매개변수로 람다식을 넣어주면 노란색 경고가 사라진다.
즉 파라미터로 람다식을 갖는 함수는 inline으로 작성하면 성능 향상을 기대할 수 있다. 하지만 break 등의 키워드를 사용하면 예상하지 못한 결과를 얻을 수 있다.
매개변수 out1과 out2 모두 람다식이다.
하지만 out2는 noinline 키워드를 사용했다. out2 에 전달되는 함수는 인라인으로 전달되지 않고 그대로 남아있다.
fun main() {
fun1(3){x->println("a : $x")}
}
inline fun fun1(a:Int, fun2:(Int)->Unit){
println("Hello")
fun2(a)
println("ByeBye")
}
main에서 inline 함수인 fun1을 호출하는 코드이다
fun1은 매개변수로 람다함수 fun2를 갖는다.
Hello
a : 3
ByeBye
main에서 람다함수를 정의해서 fun1의 인자로 전달하는데 이 람다함수에 return을 넣어보자
fun main() {
fun1(3){
println("a : $it")
return
}
}
inline fun fun1(a:Int, fun2:(Int)->Unit){
println("Hello")
fun2(a)
println("ByeBye")
}
Hello
a : 3
fun2즉 람다함수에 main에서 정의한 람다함수가 인자로 전달되므로 해당 함수에서 return으로 빠져나오고 ByeBye는 출력될 것 같지만 fun1 자체를 return으로 빠져나가 버린다. 즉 ByeBye는 출력되지 않는다. 이것을 비지역 반환이라 한다.
이런 경우를 막기 위해서 return을 사용하지 않으면 된다.
강제적으로 return 사용을 막으려면 crossinline 키워드를 사용한다.
crossinline 키워드를 사용하자 return에 빨간 줄이 표시된다.
클래스의 멤버 함수를 외부에서 추가할 수 있다.
기존의 표준 라이브러리를 수정하지 않고 확장할 수 있다!
너무 많이 사용하면 호환성이 떨어질 수 있다.
fun main() {
var name = "Tom"
println(name.addBabo())
}
fun String.addBabo():String{
return this+" Babo"
}
Tom Babo
String에 addBabo라는 확장함수를 추가한다.
this는 함수 호출 대상을 가리킨다. 위의 예시에서는 main의 "Tom"이다.