[Android(Kotlin)] kotlin 기초 - 2

업데이트:

카테고리:

태그: ,

3. 함수

3. 1. 함수 선언

코틀린에서 함수를 선언하는 방법은 크게 2가지이다.

일반적인 함수 선언 방법

fun sum(a : Int , b : Int) : Int {
    return a + b
}

/*
fun 함수명 (입력값 명 : 입력 타입) : 반환 타입{
		
		내용

		return 반환값
}
*/

위의 방법으로 선언한 함수의 구조는 Java와 크게 다르지 않다.

표현식 선언 방법

fun sum(a : Int , b : Int) = a + b

위와 같은 방법으로 함수를 더욱 간결하게 표현할 수 있으며 이 경우 컴파일러가 반환 타입을 추론할 수 있으므로 반환 타입을 명시하지 않아도 된다.

3. 2. 고차함수, 익명 함수, 람다

Kotlin에서 함수는 일급 객체(first-class)로, 함수가 일반 객체와 같이 취급될 수 있다. 변수에 할당되거나 자료구조에 사용될 수 있고 다른 함수의 매개변수로 전달되거나 반환값으로 이용될 수 있다.

매개변수로 함수를 받거나 다른 함수를 반환값으로 가지는 함수를 고차함수라 부른다.

fun transformation( f : (String, Int) -> String) : String {
    return f("hello",3)
}

위의 예시에서 매개변수로 선언된 f는 함수 타입으로, String 과 Int를 입력받아 String으로 반환하는 함수를 나타낸다.

이러한 함수 타입의 인스턴스를 얻기 위해서는 다음과 같은 방법을 사용할 수 있다.

람다 표현식

{str, num -> str + num.toString()}

익명 함수

fun(str : String, num : Int) : String{
    return str + num.toString()
}

함수 참조

String::toInt

3. 3. 범위 함수

범위 함수는 특정 코드 블록을 한 객체의 범위 내에서 실행하고 싶을 때 사용하는 특별한 함수로 let, apply, run, also, with으로 총 5가지가 있다.

범위 함수의 일반적인 사용 예시는 다음과 같다.

Person("Alice", 20, "Amsterdam").let {
    println(it)
    it.moveTo("London")
    it.incrementAge()
    println(it)
}

이 코드를 let 없이 작성한다면 다음과 같다.

val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)

범위 함수는 기술적으로 특별한 점은 없지만 코드를 좀더 깔끔하고 가동성있게 만들 수 있다.

5가지의 범위함수는 블록안에서 컨텍스트 개체를 지칭하는 방법과 반환값등의 차이가 있는데 이를 요약하자면 다음과 같다.

  • let : 컨텍스트 객체는 묵시적으로 it이 되고 마지막 표현식의 결과를 반환한다. it 대신 명시적인 변수명을 사용할 수 있다.

  • apply : 컨텍스트 객체는 this가 되며 컨텍스트 객체 자신을 반환한다.

  • run : 컨텍스트 객체는 this가 되며 마지막 표현식의 결과를 반환한다.

  • also : 컨텍스트 객체는 it이 되며 컨텍스트 객체 자신을 반환한다.

  • with : 컨텍스트 객체는 this가 되며 마지막 표현식의 결과를 반환한다. 함수의 인자로 객체가 필요하다는 점에서 run과 차이가 있다.

다음은 공식 문서에 적혀있는 범위 함수 선택 가이드이다.

  • null이 아닌 객체에 대해 코드 블록 실행 : let
  • 로컬 범위에서 변수로서의 표현식 실행 : let
  • 객체 초기화 : apply
  • 객체를 초기화하면서 결과값을 계산 : run
  • 표현식이 필요한 실행문 : run
  • 부수적인 효과 : also
  • 객체의 함수 호출을 그룹핑 : with

일례로 nullable 객체에 대해 안전하게 코드를 실행하고 싶다면 다음과 같이 let을 사용할 수 있다.

val a : String = makeString()
a?.let {
    // do something
}

4. 클래스 (Class)

class 키워드를 이용해 클래스를 선언할 수 있다.

class Adder {
    var a : Int = 0
    var b : Int = 0

    val sum : Int
        get() {
            return a + b
        }
}

Kotlin에서는 클래스 내부에 선언한 변수를 프로퍼티(property)라 부르며 프로퍼티는 실제 값을 가지는 필드와 get, set등의 접근자 함수로 이루어져 있다. 접근자 함수는 프로퍼티 선언 시 기본적으로 제공되며, 커스텀 접근자 함수를 선언할 수 도 있다.

class Adder {
    // 기본 제공 get, set 사용 가능
    var a : Int = 0
    var b : Int = 0

    // 읽기 전용 프로퍼티, 커스텀 get
    val sum : Int
        get() {
            return a + b
        }
}

접근자 함수를 호출하는 코드는 함수를 호출하지 않고 프로퍼티명을 그대로 사용한다. Kotlin에서는 객체를 생성할 시 new 키워드가 필요없다.

val adder = Adder() // 객체생성
adder.a = 1 // a의 set 접근자 호출
adder.b = 2 // b의 set 접근자 호출
println(adder.sum) // sum의 get 접근자 호출

프로퍼티를 생성자에 선언하는 것으로 클래스 선언이 더 간단해질 수도 있다.

class Person(val name : String)

클래스에 함수가 없이 값만 필요한 경우 중괄호를 생략할 수 있고 이러한 클래스를 value object라 부른다. Kotlin에서는 data키워드를 통해 value object를 선언할 수 있다.

data class Person(val name : String)

위와 같이 data 클래스를 선언할 경우 컴파일러는 다음과 같은 일을 해준다.

  • equals() / hashCode() 생성
  • toString()의 결과를 “Person(name = person1 )” 형태로 변형
  • componentN() 생성