함수와 람다
함수
함수 선언
코틀린에서 함수는 fun키워드 사용해서 선언
fun double(x: Int): Int {
return x*2
}
함수 사용 전통적인 방식으로 함수 호출
val result = double(2)
멤버 함수 호출은 점 부호를 사용
Sample().foo() // Sample클래스의 인스턴스를 생성하고 foo를 호출
파라미터
파라미터 표기법(name: type)을 사용해서 파라미터 정의 / 각 파라미터 콤마로 구분
fun powerOf(number: Int, exponent: Int) {
...
}
기본 인자
함수 파라미터는 기본 값을 가질 수 있다. 이 경우 대응하는 인자를 생략하면 기본 값을 사용한다
이는 다른 언어와 비교해 오버로딩 함수의 개수를 줄여준다
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
...
}
타입 뒤에 등호(=)와 값을 사용해서 기본 값을 정의
오버라이딩 메서드는 항상 베이스 메서드와 같은 기본 파라미터 값을 사용한다. 기본 파라미터 값을 갖는
메서드를 오버라이딩 할 때, 시그니처에 기본 파라미터를 값을 생략해야 한다
open class A {
open fun foo(i: Int = 10) { ... }
}
class B : A() {
override fun foo(i: Int) { ... } // 기본 값을 허용하지 않음
}
기본 값을 갖는 파라미터가 기본 값이 없는 파라미터보다 앞에 위치하면,
이름 가진 함수를 호출할 때에만 기본 값을 사용한다
fun foo(bar: Int = 0, baz: Int) { }
foo(baz = 1) // 기본 값 bar = 0 사용
하지만 함수 호출시 마지막 인자를 괄호 밖에 람다로 전달하면, 기본 파라미터에 값을 전달하지 않는 것을 허용
fun foo(bar: Int = 0, baz: Int = 1, qux() -> Unit) { ... }
foo(1) { println("hello") } // 기본 값 baz = 1 사용
foo { println("hello") } // 기본 값 bar = 0, baz = 1 사용
Unit 리턴 함수
함수가 어떤 유용한 값도 리턴하지 않으면, 리턴 타입으로 Unit을 사용
Unit은 Unit을 유일한 값으로 갖는 타입. 이 값을 명시적으로 리턴하면 안 된다
fun printHello(name: String?): Unit {
if(name != null)
println("hello ${name}")
else
println("hi")
// 'return Unit' 또는 'return' 생략
}
리턴 타입으로 Unit을 선언하는 것 또한 생략 가능. 위 코드는 다음과 동일
fun printHello(name: String?) {
...
}
단일 식 함수
함수가 단일 식을 리턴할 때 중괄호를 생략하고 등호(=) 뒤에 몸체로 단일 식을 지정할 수 있다
fun double(x: Int): Int = x*2
컴파일러가 리턴 타입을 유추할 수 있으면 리턴 타입을 명시적으로 선언하는 것을 생략할 수 있다
fun double(x: Int) = x*2
명시적 리턴 타입
블록 몸체를 갖는 함수는 Unit 을 리턴한다는 것을 의도하지 않는 이상 항상 리턴 타입을 명시적으로 지정해야 한다. Unit을 리턴하는 경우 생략 가능하다 . 코틀린은 블 록 몸체를 가진 함수의 리턴 타입을 유추할 수 없다. 왜냐면 그런 함수가 복잡한 제어 흐름을 가지면 리턴 타입을 독자가 (그리고 때때로 컴파일러 조차도) 알 수 없기 때문이다.
함수 범위
코틀린은 함수를 파일에서 최상위 수준으로 선언할 수 있다. 이는 자바, C#, 스칼라와 달리 함수를 포함할 클래스를 만들 필요가 없다는 것을 의미한다. 최상위 수준 함수뿐 만 아니라 함수를 로컬로, 멤버 함수로, 확장 함수로 선언할 수 있다.
로컬 함수
코틀린은 다른 함수 안에 선언한 로컬 함수를 지원
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if(!visited.add(current)) return
for(v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
로컬 함수는 외부 함수의 로컬 변수에 접근할 수 있으며, 위 경우에 visited를 로컬 변수로 할 수 있다
fun dfs(graph: Graph) {
val visited = HashSet<Vertex>()
fun dfs(current: Vertex) {
if(!visited.add(current)) return
for(v in current.neighbors)
dfs(v)
}
dfs(graph.vertices[0])
}
멤버 함수
멤버 함수는 클래스나 오브젝트에 선언된 함수이다
class Sample() {
fun foo() { println("Foo") }
}
점 부호를 사용해서 멤버 함수를 호출한다
Sample().foo() // Sample클래스의 인스턴스를 생성하고 foo를 호출