함수
코틀린에서는 함수를 정의하기 위해 별도의 클래스가 필요하지 않습니다. 이러한 단독함수(standalone function)는 다른 클래스나 또는 또다른 단독함수에서 재사용이 가능합니다.
또한 패키징 역시 같이 반영되기 때문에, 개발자가 원하는 위치에 원하는 함수를 위치 시킬 수 있습니다.
함수 생성
1 | // 일반적인 정의 |
함수의 정의는 fun 이라는 예약어로 시작하며, 함수 이름, 파라메터, 리턴 타입 순으로 정의됩니다. 여기서 파라메터는 또 변수 명: 타입
순으로 작성합니다.
따라서 addOne
함수를 해석하면 i 라는 이름의 정수형 파라메터를 하나 받아 정수형 값을 리턴한다고 해석 할 수 있습니다.
두번째 방식의 경우 일반적인 자바와는 형태가 조금 다른데, 이와 같이 단일 표현식의 경우 = 을 통해 함수를 정의할 수 있습니다. 또한 이 경우 별도의 return 예약어를 사용하지 않더라도 표현식의 마지막 문장의 결과가 리턴되게 되며 또한 반환 타입 역시 별도의 선언없이 표현식의 결과 타입에 따라 결졍됩니다. 그리고 또한 이러한 암시적인 리턴타입은 컴파일 타임에 결정됩니다.
따라서 아래의 경우 컴파일러에서 에러를 발생시킵니다.
1 | val id: String = addTwo(3) // ERROR! |
다만 외부에서 참조하는 경우가 많은 함수라면 명시적으로 타입을 표현해주는 것도 좋다. 왜냐하면 나중에 해당 함수를 사용할 사용자가 이해하기 좋으며, 또한 함수 내용이 변경되었을 때, 뜻하지 않게 타입이 바뀌는 경우도 막을 수 있습니다.
Unit타입
Unit타입은 자바의 void 와 대응되는 타입입니다. 함수내에서 아무것도 리턴할게 없는 경우 Unit1을 사용하면 됩니다.
1 | fun printMsg(msg:String) = println(msg) |
위 코드의 실행 결과는 msg is kotlin.Unit
으로 표시된다. 보이는 것 처럼 Unit 함수의 경우 Unit 객체를 리턴하고, Unit 객체 내부에는 기본적인 toString, equals, hashcode 가 정의 되어 있기 때문에, 위와 같은 결과를 얻을 수 있습니다. 또한 이로인해 코틀린의 모든 함수는 표현식으로 취급될수 있고, 모든 함수 결과에 메소드를 호출 할 수 있습니다.
파라메터
파라메터는 위에서 명시한대로 타입을 정확히 명시해야한다. 위 addOne, addTwo 함수에서는 모두 i 라는 정수형의 파라메터를 하나 받는것을 알 수 있습니다.
1개 이상의 파라메터가 필요한 경우, 콤마(,) 를 사이에 두어 구분하며 추가 할 수 있습니다.
다만 변수선언과는 다르게 var, val 은 붙지 않는데, val 처럼 값의 변경은 불가능합니다.
1 | fun testFun(i: Int) { |
블록바디
함수를 정의하는데 =를 사용하는 방법과 {} 블록을 사용하는 방식 두가지가 있습니다.
블록을 사용하여 정의하는 경우 리턴타입을 꼭 정해야 하며, 명시하지 않은 경우 Unit으로 지정합니다. 또한 return 역시 명시적으로 표현해야 합니다.
조심해야하는 점은 =와 {} 블록을 병기하는 경우인데, 이 경우는 리턴 타입이 람다 타입으로 추론합니다.
1 | fun lambdaGen() = {1} |
위 코드에서 처럼 실행 결과처럼 lambdaGen 함수를 실행했을 때 1이라는 값이 리턴되는것이 아닌 1을 리턴하는 람다를 리턴하고 이 리턴된 람다를 실행했을 때, 의도한 1이라는 값이 나오게 됩니다.
파라메터 기본 값
코틀린은 함수 파라메터에 기본값을 지정 할 수 있습니다.
1 | fun addOne(i: Int = 1) = i + 1 |
파라메터가 있을 때도 정상적으로 처리하고 파라메터가 없는 경우 기본 값으로 설정된 1로 처리되는 것을 확인할 수 있습니다.
이러한 파라메터 기본 값으로 원래 있는 함수에 파라메터를 추가할 때도 기존 코드의 영향을 줄이고 수정 할 수 있게 됩니다.
파라메터의 기본 값은 파라메터의 위치와 무관하게 지정 할 수 있으나 일반 파라메터 보다 앞에 있을 경우 일반 파라메터에 파라메터를 넘기게 하기 위해 결국 모든 파라메터를 넘겨야하기 때문에, 이런식으로 정의하는 것은 피해야합니다.
1 | fun add(a:Int = 1, b: Int) = a + b |
다만 파라메터를 명시적으로 지정하는 경우에는 가능합니다.
또한 파라메터는 리터럴 값 외의 표현식으로 사용 할 수도 있습니다.
1 | fun numAndMsg(i: Int, msg:String = "i is ${i}") = i to msg |
메소드가 실행되는 과정에 기본값을 초기화 한 후 메소드가 실행됩니다. 그리고 기본 값 파라메터를 설정한 경우 표현식을 실행하지 않습니다.
이때 위 함수에서 파라메터 순서를 바뀌게 되면 msg는 i의 존재를 모르기 때문에, 컴파일이 불가능 합니다.
명시적 파라미터
코틀린은 함수 실행시 명시적으로 파라메터를 지정할 수 있습니다.
1 | fun add(a:Int = 1, b: Int) = a + b |
위 코드 처럼 b 파라메터에 대해 명시적으로 할당하여 사용하는 것을 볼 수 있습니다.
명시적 파라메터로 가독성이 올라가 코드를 이해 하는데 많은 도움이 됩니다.
1 | fun createUser(name: String, age: Int) = name to age |
가변 인자
단일 파라메터상의 여러개의 값을 넣을 수 있는 형태의 파라메터 입니다.
1 | fun max(vararg arr:Int):Int = intArrayOf(*arr).maxOrNull()?:0 |
위 max 함수의 경우 가변 인자로 넘어온 숫자들을 arr라는 이름의 배열(Array<out T>
)에 저장하고 사용하는 모습을 보여줍니다.
intArrayOf는 마찬가지로 가변인자로 int 들을 받아 IntArray를 생성하는 함수 입니다. 이 함수를 사용하기 위해 가변 변수인 arr를 스프레드 연산자('
)를 통해 전달하는 것을 보실 수 있습니다.
가변인자를 사용하기 위해서는 함수 파라메터의 가장 마지막(마지막 파라메터가 람다인 경우엔 람다 앞)에 위치 해야합니다.
Destructing
코틀린은 Pair 등 Map.Entry 혹은 componentN 함수를 가지고 있는 타입에 대해 Destructing 을 지원합니다.
1 | val (a, b) = 1 to 2 |
to 는 pair를 만드는 코틀린 내장 함수 입니다. Pair는 Destructing 을 지원하기 때문에 두개의 변수에 각각 할당하는 것을 볼 수 있습니다.
또한 람다 파라메터 에서도 사용가능합니다.
1 | map.mapValues { entry -> "${entry.value}!" } |
그리고 사용하지 않는 파라메터는 밑줄로 치환하여 해당 파라메터를 사용하지 않게 할 수도 있습니다.
1 | map.mapValues { (_, value) -> "$value!" } |
출처
- 다재다능 코틀린 프로그래밍
- 코틀린 공식 문서
1. Unit이라는 이름은 타입 이론에서 아무런 정보를 갖지않는 싱글톤인 Unit에서 유래