•
Kotlin 함수는 fun 키워드를 사용하여 선언된다.
fun double(x: Int): Int {
return 2 * x
}
Kotlin
복사
함수 사용
•
함수는 표준 접근 방식을 사용하여 호출된다.
val result = double(2)
Kotlin
복사
•
멤버 함수를 호출할 때는 점 표기법을 사용한다.
Stream().read() // create instance of class Stream and call read()
Kotlin
복사
매개변수
•
함수 매개변수는 Pascal 표기법(name: type)을 사용하여 정의된다.
•
매개변수는 쉼표로 구분하고 각 매개변수는 명시적으로 입력해야 한다.
fun powerOf(number: Int, exponent: Int): Int { /*...*/ }
Kotlin
복사
•
함수 매개변수를 선언할 때 끝에 쉼표를 사용할 수 있다.
fun powerOf(
number: Int,
exponent: Int, // trailing comma
) { /*...*/ }
Kotlin
복사
기본 인수
•
함수 매개변수는 기본값을 가질 수 있으며 이는 해당 인수를 건너뛸 때 사용된다.
fun read(
b: ByteArray,
off: Int = 0,
len: Int = b.size,
) { /*...*/ }
Kotlin
복사
•
기본값은 타입에 = 를 추가하여 설정된다.
•
오버라이딩 메서드는 항상 기본 메서드의 기본 매개변수 값을 사용한다. (자식 클래스에서 설정 불가능)
•
기본 매개변수 값이 있는 메서드를 오버라이딩할 때는 기본 매개변수 값을 시그니처에서 생략해야 한다.
open class A {
open fun foo(i: Int = 10) { /*...*/ }
}
class B : A() {
override fun foo(i: Int) { /*...*/ } // No default value is allowed.
}
Kotlin
복사
•
기본 매개변수가 기본값이 없는 매개변수보다 앞에 오는 경우 명명된 인수로 함수를 호출하여야만 기본값을 사용할 수 있다.
fun foo(
bar: Int = 0,
baz: Int,
) { /*...*/ }
foo(baz = 1) // The default value bar = 0 is used
Kotlin
복사
•
기본 매개변수 뒤에 있는 마지막 인수가 람다인 경우 명명된 인수로 전달하거나 괄호 밖으로 전달할 수 있다.
fun foo(
bar: Int = 0,
baz: Int = 1,
qux: () -> Unit,
) { /*...*/ }
foo(1) { println("hello") } // Uses the default value baz = 1
foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1
foo { println("hello") } // Uses both default values bar = 0 and baz = 1
Kotlin
복사
명명된 인수
•
함수를 호출할 때 하나 이상의 인수에 이름을 지정할 수 있다.
•
이는 함수에 인수가 많고 인수와 값을 연관시키기 어려울 때 특히 부울이나 null 값인 경우 유용할 수 있다.
•
함수 호출에서 명명된 인수를 사용하면 나열된 순서를 자유롭게 변경할 수 있다.
•
기본값을 사용하려면 이러한 인수를 모두 제외하면 된다.
// 함수 예시
fun reformat(
str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ',
) { /*...*/ }
// 모든 인수의 이름을 지정하지 않은 경우
reformat(
"String!",
false,
upperCaseFirstLetter = false,
divideByCamelHumps = true,
'_'
)
// 기본값이 있는 인수를 건너뛰는 경우
reformat("This is a long String!")
// 특정 인수를 건너뛰는 경우 (모든 후속 인수를 명명해야함)
reformat("This is a short String!", upperCaseFirstLetter = false, wordSeparator = '_')
Kotlin
복사
•
spread 연산자 * 를 사용하여 이름이 포함된 가변 개수의 인수를 전달할 수 있다.
fun foo(vararg strings: String) { /*...*/ }
foo(strings = *arrayOf("a", "b", "c"))
Kotlin
복사
Java 함수를 호출할 땐 명명된 인수를 사용할 수 없기 때문에 순서대로 인자를 전달해야 한다.
Unit 반환 함수
•
함수가 유용한 값을 반환하지 않으면 반환 유형은 Unit이다.
•
Unit은 값이 하나뿐인 타입이다.
•
이 값은 명시적으로 반환할 필요가 없다.
fun printHello(name: String?): Unit {
if (name != null)
println("Hello $name")
else
println("Hi there!")
// `return Unit` or `return` is optional
}
Kotlin
복사
•
Unit 반환 타입 선언을 생략할 수 있다.
fun printHello(name: String?) { ... }
Kotlin
복사
단일 표현식 함수
•
함수 본문이 단일 표현식으로 구성된 경우 중괄호를 생략하고 본문을 = 뒤에 지정할 수 있다.
fun double(x: Int): Int = x * 2
Kotlin
복사
•
컴파일러가 이를 유추할 수 있는 경우 반환 타입을 명시적으로 선언하지 않아도 된다.
fun double(x: Int) = x * 2
Kotlin
복사
명시적 반환 타입
•
블록 본문이 있는 함수는 반환 타입을 항상 명시적으로 지정해야 한다.
•
다만 Unit 반환이 의도된 경우에는 반환 타입을 지정하는 것이 선택 사항이다.
•
Kotlin은 블록 본문이 있는 함수의 반환 타입을 유추하지 않는다.
•
이러한 함수는 본문에서 복잡한 제어 흐름을 가질 수 있고 반환 타입이 코드 작성자 또는 컴파일러에게 명확하지 않을 수 있기 때문이다.
가변 개수의 인수
•
함수의 매개변수에 vararg 수정자를 붙여서 가변 개수의 인자를 받을 수 있다.
•
하나의 매개변수만 vararg로 지정할 수 있다.
•
vararg 매개변수가 매개변수 목록의 마지막이 아닐 경우 이후 매개변수 값은 명명된 인수로 전달해야 한다.
•
함수 타입인 경우에는 괄호 밖에서 람다를 전달하여 사용할 수 있다.
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
Kotlin
복사
•
이 경우 함수에 가변 개수의 인자를 전달할 수 있다.
•
배열의 내용을 함수에 전달하고 싶다면 스프레드 연산자 * 를 사용한다.
// 인자를 개별적으로 전달하는 경우
val list = asList(1, 2, 3)
// 배열의 내용을 함수에 전달하는 경우
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
// 원시 타입 배열의 내용을 함수에 전달하는 경우
val a = intArrayOf(1, 2, 3) // IntArray is a primitive type array
val list = asList(-1, 0, *a.toTypedArray(), 4)
Kotlin
복사
•
함수 내에서 vararg 타입의 매개변수는 Array<T>로 보인다.
•
예제에서는 ts 변수가 Array<out T> 타입으로 선언되어 있다.
중위 표기법
•
infix 키워드로 표시된 함수는 중위 표기법(호출 시 점과 괄호 생략)을 사용하여 호출할 수 있다.
•
다음과 같은 요구사항을 충족해야 한다.
◦
멤버 함수나 확장 함수여야 한다.
◦
매개변수가 하나여야 한다.
◦
매개변수는 가변 인자를 허용하지 않아야 하며 기본값이 없어야 한다.
infix fun Int.shl(x: Int): Int { ... }
// 인픽스 표기법을 사용한 함수 호출
1 shl 2
// 이는 다음과 같습니다:
1.shl(2)
Kotlin
복사
•
infix 함수 호출은 산술 연산자, 타입 캐스트, rangeTo 연산자보다 낮은 우선순위를 가진다.
'1 shl 2 + 3' 은 '1 shl (2 + 3)' 과 같습니다.
'0 until n * 2' 는 '0 until (n * 2)' 와 같습니다.
'xs union ys as Set<*>' 는 'xs union (ys as Set<*>)' 와 같습니다.
Kotlin
복사
•
infix 함수 호출은 &&와 ||, is 및 in 체크 그리고 몇몇 다른 연산자보다 높은 우선순위를 가진다.
'a && b xor c' 는 'a && (b xor c)' 와 같습니다.
'a xor b in c' 는 '(a xor b) in c' 와 같습니다.
Kotlin
복사
•
infix 함수는 항상 수신자와 매개변수가 모두 명시되어야 한다.
•
현재 수신자에서 메서드를 호출할 때 중위 표기법을 사용하는 경우 명시적으로 this를 사용해야 한다.
class MyStringCollection {
infix fun add(s: String) { /*...*/ }
fun build() {
this add "abc" // 올바름
add("abc") // 올바름
// add "abc" // 잘못됨: 수신자가 명시되어야 함
}
}
Kotlin
복사
함수 범위
•
Kotlin 함수는 파일의 최상위 수준에서 선언할 수 있으므로 함수를 보관하기 위한 클래스를 만들 필요가 없다.
•
Kotlin 함수는 최상위 수준 함수 외에도 멤버 함수 및 확장 함수로 로컬에서 선언할 수 있다.
지역 함수
•
Kotlin은 다른 함수 내부의 함수인 지역 함수를 지원한다.
•
지역 함수는 외부 함수의 지역 변수에 엑세스할 수 있다.
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])
}
Kotlin
복사
멤버 함수
•
멤버 함수는 클래스나 객체 내부에 정의된 함수이다.
class Sample {
fun foo() { print("Foo") }
}
Kotlin
복사
•
멤버 함수는 점 표기법으로 호출된다.
Sample().foo() // creates instance of class Sample and calls foo
Kotlin
복사
제네릭 함수
•
함수는 제네릭 매개변수를 가질 수 있으며 이는 함수 이름 앞에 꺾쇠 괄호를 사용하여 지정된다.
fun <T> singletonList(item: T): List<T> { /*...*/ }
Kotlin
복사
꼬리 재귀 함수
•
Kotlin은 tail recursion이라고 알려진 함수형 프로그래밍 스타일을 지원한다.
•
이 스타일을 사용하면 일반적으로 루프를 사용할 알고리즘을 재귀 함수로 대체할 수 있으며 스택 오버플로우의 위험 없이 동작할 수 있다.
•
함수가 tailrec 수정자로 표시되고 필요한 형식 조건을 충족하면 컴파일러는 재귀를 최적화하여 빠르고 효율적인 루프 기반 버전으로 변환한다.
// 전통적인 스타일의 코드
val eps = 1E-10
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if (Math.abs(x - y) < eps) return x
x = Math.cos(x)
}
}
// tail resursion 스타일의 코드
val eps = 1E-10
tailrec fun findFixPoint(x: Double = 1.0): Double =
if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))
Kotlin
복사
•
tailrec 수정자를 사용하려면 함수가 자신을 호출할 때 그것이 마지막 작업이어야 한다.
•
재귀 호출 이후에 더 많은 코드가 있거나 try/catch/finally 블록 내에서 호출하거나 열린 함수에서 사용할 수 없다.