안드로이드/안드로이드 Kotlin

[코틀린-Kotlin Bootcamp] 3. Functions

요빈 2023. 3. 8. 01:04

함수

fun 키워드를 사용해 함수를 정의한다.

다른 언어들과 마찬가지로 괄호는 함수 인수, 중괄호는 함수의 코드를 구성한다.

fun printHello() {
    println ("Hello World")
}

printHello()

 

다른 언어와 마찬가지로 코틀린 또한 main() 함수를 통해 실행을 위한 진입점을 지정한다.

모든 명령줄 인수는 문자열 배열로 전달된다.

fun main(args: Array<String>) {
    println("Hello, world!")
}

코틀린의 모든 함수는 명시적으로 지정된 것이 없는 경우에도 무언가를 반환한다. 

따라서 위 main() 함수와 같이 리턴값이 없는 함수는 kotlin.Unit 유형을 반환하며 이는 코틀린에서 값이 없다고 말하는 방식이다.

즉, 코틀린에서의 거의 모든 것은 값을 가진다는 의미이다.

 

일부 다른 언어에서는 값이 없는 코드인 명령문들이 있다.

하지만 코틀린에서는 거의 모든 코드가 표현식이며 값이 kotlin.Unit인 경우에도 값이 있다.

 

메서드의 기본값 

코틀린에서는 매개변수(인수)의 기본값을 지정할 수 있다.

호출자가 인수를 제공하지 않으면 기본값이 사용된다.

나중에 메서드(멤버함수)를 작성할 때 동일한 메서드의 오버로드 버전을 많이 작성하지 않아도 된다는 의미이다.

아래 함수에서는 매개변수인 speed값의 기본값을 fast로 지정하였다.

fun swim(speed: String = "fast") {
   println("swimming $speed")
}

매개변수에 대해 기본값이 지정되지 않은 경우엔 해당 인수가 항상 전달되어야 한다.

또한 매개변수의 기본값이 꼭 값(value)일 필요는 없으며, 함수일 수도 있다.

 

압축 함수

아래 코드를 보면 적은 양의 코드에 많은 논리를 압축한다.

fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        temperature > 30 -> true
        dirty > 30 -> true
        day == "Sunday" ->  true
        else -> false
    }
}

압축을 조금 풀고 싶거나 확인 조건이 더 복잡한 경우, 지역변수를 사용할 수 있다.

하지만 코틀린에서는 압축 기능을 사용한다. 

 

압축 함수 또는 단일 표현식 함수는 코틀린의 일반적인 패턴이다.

압축함수(단일 표현식 함수)는 코드를 더 간결하고 윍기 쉽게 만들고 테스트를 위한 코드 경로 수를 줄이는 역할을 한다.

압축 함수는 함수의 결과를 반환할 때 =(등호) 뒤에 함수 본문을 작성하고, 중괄호와 리턴문을 생략한다.

fun isTooHot(temperature: Int) = temperature > 30

fun isDirty(dirty: Int) = dirty > 30

fun isSunday(day: String) = day == "Sunday"

 

필터

필터는 일부 조건에 따라 리스트의 일부를 가져오는 편리한 방법이다.

필터 구조는 list.filter { it(iterator) ~ }와 같다.

필터 조건에 대한 코드는 중괄호 안에 있으며 필터가 반복될 때 각 항목을 참조한다.

조건식이 true를 반환하면 해당 항목이 포함된다.

fun main() {
	val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
	val eager = decorations.filter {it[0] == 'p'} // eager, create a new list
	println("eager : $eager")
    
	val lazy = decorations.asSequence().filter {it[0] == 'p'} // lazy, will wait until asked to evaluate
	val lazyList = lazy.toList() // force evaluation of the lazy list
	println("lazyList : $lazyList")
}

코틀린의 필터는 필요한 방식으로 실행되지만 기본적으로는 eager한 편으로 사용할 때마다 리스트가 생성된다.

필터를 lazy하게 하려면 한 번에 하나의 항목만 볼 수 있는 컬렉션인 Sequence를 사용해 처음부터 끝까지 사용할 수 있다.

시퀀스를 리스트로 변환하기 전까지는 리스트가 생성되지 않는다.

즉, eager -> 바로 리스트 생성

      lazy -> 요청될 때 까지 리스트 생성 안함

 

시퀀스 및 Lazy Evaluation에서 진행중인 작업을 시각화하려면 map() 함수를 사용한다.

map() 함수는 시퀀스의 각 요소를 간단하게 변환한다.

 

Lambdas

람다는 함수를 만드는 표현식으로, 명명된 함수를 선언하는 대신 이름 없는 함수를 선언한다.

람다식을 데이터로 전달할 수 있다는 점이 가장 유용한 점 중 하나이다.

 

람다 표현식은 중괄호 내에 정의된다.

람다 또한 매개변수를 가질 수 있는데 람다의 매개변수는 함수 화살표 -> 왼쪽에 위치한다. 

실행할 코드는 함수 화살표 오른쪽에 위치한다. 람다가 변수에 할당되면 함수처럼 호출할 수 있다.

아래 코드에서 매개변수는 dirty, 실행할 코드(함수 내용)은 dirty / 2이다.

var dirtyLevel = 20
val waterFilter = { dirty : Int -> dirty / 2}
println(waterFilter(dirtyLevel))

또한 람다는 함수를 포함하는 변수 선언에 중요하게 사용된다.

// 기본 자료형 선언
val example: Int
// 함수(람다 사용)를 포함한 자료형 선언
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }

위 코드 내용은 다음과 같다.

   - waterFilter라는 변수를 만든다.

   - waterFilter는 Int를 매개변수로 받아 Int를 반환하는 모든 함수가 될 수 있다.

   - waterFilter에 람다를 할당해 dirty를 2로 나눈 값을 반환한다.

* 람다 인수(dirty)는 유형 유추에 의해 계산되므로 유형을 따로 지정할 필요 없다.

 

고차 함수(High-order function)

고차 함수는 람다 식과 같은 함수를 다른 함수의 데이터로 전달하는 형식을 말한다.

필터 또한 고차 함수이며 조건으로 필터링 할 람다식을 전달하였다.

람다의 진정한 힘은 한 함수에 대한 인수가 다른 함수인 고차 함수를 만드는데 사용된다.

아래 함수는 고차 함수이다. 첫 번째 인수는 정수이고, 두 번째 정수는 정수를 받아 정수를 반환하는 함수이다.

fun updateDirty(dirty: Int, operation: (Int) -> Int): Int {
   return operation(dirty)
}

val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
println(updateDirty(30, waterFilter))

위 예시처럼 전달하는 함수가 람다로 표현될 필요는 없으며 일반 네임드 함수도 가능하다.

일반 함수를 인수로 지정하려면 :: 연산자를 사용하여야 한다.

fun increaseDirty( start: Int ) = start + 1

println(updateDirty(15, ::increaseDirty))

고차 함수를 통해 코틀린은 함수를 호출하는 것이 아니라 함수 참조를 인수로 전달하고 있음을 알 수 있다.

 

* 아래 과정을 공부하며 작성한 글입니다.

https://developer.android.com/codelabs/kotlin-bootcamp-functions#0