// 나쁜 예
// user가 for loop 외부에 존재
var user: User
for (i in users.indices) {
user = users[i]
print(user)
}
// 좋은 예
// user가 for loop 내부에 존재
for (i in users.indices) {
val user = users[i]
print(user)
}
// 더 좋은 예
// user가 for loop 내부에 존재
for ((i, user) in users.withIndex()) {
print(user)
}
스코프가 좁을수록 프로그램을 추적하고 관리하기 쉽다.
여러 프로퍼티를 한번에 설정해야 하는 경우 **구조분해 선언(destructuring declaration)**을 활용한다.
// 나쁜 예
fun updateWeather(degrees: Int) {
val description: String
val color: Int
if (degrees < 5) {
description = "cold"
color = Color.BLUE
} else if (degrees < 23) {
description = "mild"
color = Color.YELLOW
} else {
description = "hot"
color = Color.RED
}
}
// 좋은 예
fun updateWeather(degrees: Int) {
val (description, color) = when { // 구조분해 선언
degrees < 5 -> "cold" to Color.BLUE
degrees < 23 -> "mild" to Color.YELLOW
else -> "hot" to Color.RED
}
}
캡처링
시퀀스를 활용해 에라토스테네스의 체(소수를 구하는 알고리즘)를 구하면 다음과 같다.
val primes = sequence {
var numbers = generateSequence(2) { it + 1 }
while (true) {
val prime = numbers.first()
yield(prime)
numbers = numbers.drop(1).filter { it % prime != 0 }
}
}
print(primes.take(10).toList()) // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
prime을 반복문 외부에 선언하면 결과가 이상하게 나온다.
val primes = sequence {
var numbers = generateSequence(2) { it + 1 }
var prime: Int // 외부에 선언
while (true) {
prime = numbers.first()
yield(prime)
numbers = numbers.drop(1).filter { it % prime != 0 }
}
}
print(primes.take(10).toList()) // [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]
시퀀스를 활용하기 때문에 filter의 연산이 지연(lazy evaluation)된다. 따라서 최종적인 prime 값으로만 filter가 평가되기 때문에 prime이 2일때 필터링된 4를 제외하고 drop만 동작한 결과를 반환한다.