일반 함수는 앞에서 다뤘으니 여기서는 람다식을 다루겠습니다. 자세한 내용은 쉽게 다가가는 최신 프로그래밍: 코틀린 - 3.3 람다 식 기초 ~ 3.5 람다 식에서 return 문 사용을 참고하기 바랍니다. 소수(prime number)는 1보다 큰 자연수 중 1과 자기 자신만을 약수(divisor)로 갖습니다. 2, 3, 5, 7, 11, 13, 17, 19, ... 가 소수입니다. 아래는 어떤 숫자가 소수인지를 판별하는 프로그램입니다. 여기서 다루려고 하는 내용은 함수 isPrime()을 람다 식으로 바꿔 구현하는 겁니다.
fun isPrime(n: Int): Boolean {
for (i in 2..<n) {
if (n % i == 0) {
println("$n is a multiple of $i ")
return false
}
}
return true
}
fun main() {
print("Enter integer value greater than 1 : ")
val x = readln().toInt()
val msg = "$x is a prime number."
if (isPrime(x)) {
println(msg)
} else {
println(msg.replace("is", "is not"))
}
}
일반 함수를 람다 식으로 바꾸려면 함수의 형식인자 타입과 반환값 타입을 람다 식의 함수 타입 선언에 그대로 반영해야 합니다. 람다 식은 표현대로 식(expression)일 뿐이며 문장(statement)이 아닙니다. 람다 식은 문장이 아니기 때문에 독립적으로 사용할 수 없습니다. if 문장에 조건식을 포함해야 하듯이, 람다 식은 할당문의 일부여야 합니다. 즉, 람다 식에서 연산한 값을 전달받을 변수(isPrimeLambda)가 필요합니다.
fun isPrime(n: Int): Boolean { ... } -> val isPrimeLambda: (Int) -> Boolean = { ... } |
또, 람다 식은 연산 결과인 값을 반환하기 때문에, 함수 블록의 문장은 값을 반환하는 형태로 바꿔야 합니다.
[함수 블록] if (n <= 1) return false -> [람다 식 블록] if (n <= 1) false |
■ 방법 1: 람다 식에서 return 문 사용
isPrime() 함수를 람다 식으로 변환할 때, 신경써야 할 부분은 for 문에서 return 문입니다. n이 i의 배수이면(n % i == 0), n이 소수가 아니므로 false 를 반환하고 함수 실행을 끝냅니다. 아래처럼 함수 isPrime()을 람다 식으로 바꾸면 어떻게 될까요? 4를 입력하면, "4 is a prime number."라는 엉뚱한 결과가 나옵니다.
val isPrimeLambda: (Int) -> Boolean = { n: Int ->
for (i in 2..<n) {
if (n % i == 0) {
println("$n is a multiple of $i ")
false
}
}
true
}
왜 그럴까요? "4 is a multiple of 2"를 출력하지만, for 루프를 빠져나오지 못하기 때문입니다. for 루프 실행을 마친 후, 마지막에 놓인 불린 값 true를 반환하기 때문입니다. 람다 식에서 return 문을 사용하는 방법을 알고 있다면(144쪽, 3.5 람다식에서 return 문 사용), 아래처럼 간단히 문제를 해결할 수 있습니다. n이 i의 배수이면, 레이블 out이 가리키는 곳으로 빠져나와, 값 false를 반환합니다.
val isPrimeLambda: (Int) -> Boolean = out@ { n: Int ->
for (i in 2..<n) {
if (n % i == 0) {
println("$n is a multiple of $i ")
return@out false
}
}
true
}
fun main() {
. . . . . .
if (isPrimeLambda(x)) {
println(msg)
} else {
println(msg.replace("is", "is not"))
}
}
■ 방법 2: 람다 식에서 return 문을 사용하지 않고 해결
람다 식에서 return 문을 사용하지 않고 해결할 수는 없을까요? return 문을 사용하는 것보다 조금 복잡하지만, 부울 타입 변수를 사용하면 됩니다. if 조건식에서 status는 앞에 놓여야 합니다. 논리 AND(&&) 연산에서 첫 번째 조건(staus)이 거짓(false)이면, 두 번째 조건(n % i == 0)은 조사하지 않기 때문입니다.
val isPrimeLambda: (Int) -> Boolean = { n: Int ->
var status: Boolean = true
for (i in 2..<n) {
if (status && n % i == 0) {
println("$n is a multiple of $i ")
status = false
}
}
status
}
■ 방법 3: 람다 타입 객체를 지역 변수로 선언
방법 1, 2에서는 람다 타입 객체 isPrimeLambda를 모두 상위 수준 변수(top-level variable)로 선언했습니다. 상위 수준 변수는 프로그램 어디에서나 이 변수를 자유롭게 참조할 수 있습니다(67쪽, 1.15 변수 범위). 상위 수준 변수는 전역 변수(global variable)과 같은 의미입니다. 아래처럼 람다 타입 객체 isPrimeLambda를 지역 변수로 선언할 수 있습니다.
fun main() {
print("Enter integer value greater than 1 : ")
val x = readln().toInt()
// 람다 식에서 return 문을 사용한 코드
val isPrimeLambda: (Int) -> Boolean = out@ { n: Int ->
. . . . . .
}
val msg = "$x is a prime number."
if (isPrimeLambda(x)) {
println(msg)
} else {
println(msg.replace("is", "is not"))
}
}
'코틀린' 카테고리의 다른 글
4장 - (아주 쉽게 설명한) 다양한 sealed 클래스를 만들어 봅시다. (0) | 2025.01.09 |
---|---|
3장 - (아주 쉽게 설명한) 함수를 람다 식으로 변환해 봅시다(2/2). (0) | 2025.01.09 |
3장 - (아주 쉽게 설명한) 조합을 계산하는 함수를 만들어 봅시다. (0) | 2025.01.09 |
2장 - (아주 쉽게 설명한) enum 클래스와 난수를 사용해 봅시다. (0) | 2025.01.09 |
코틀린: 6장 스레드와 코루틴 - 오류 정정 (0) | 2025.01.09 |