변수의 스코프를 최소화하라
// 나쁜 예 - 반복문 내에 쓰이는 변수를 외부에 두었음
var user: User
for (i in users.indices) {
user = users[i]
print("User at $i is $user")
}
// 조금 더 좋은 예
for (i in users.indices) {
val user = users[i]
print("User at $i is $user")
}
// 제일 좋은 예
for ((i, user) in users.withIndex()) {
print("User at $i is $user")
}
스코프를 최소한으로 줄이는 이유는 프로그램을 추적하고 관리하기 쉽기 때문이다. 변수의 스코프가 좁다는 것은 영향받는 범위가 좁다는 것이므로, 변경 추적에 용이하다.
변수의 경우, 미리 선언해서 할당하는 것보다 정의할 때 초기화하는 것이 좋다.
//나쁜 예 - 미리 선언
val user: User
if (hasValue) {
user = getValue()
} else {
user = User()
}
// 조금 더 좋은 예 - 정의할 때 초기화
val user: User = if(hasValue) {
getValue()
} else {
User()
}
만약 여러 개의 프로퍼티를 한번에 설정해야 한다면, 구조분해 선언을 사용하는 것이 좋다.
// 나쁜 예
fun updateWeather(degrees: Int) {
val description: String
val color: Int
if (degrees < 5) {
description = "cold"
color = Color.BULE
} else if (degrees < 23) {
desciption = "mild"
color = Color.YELLOW
} else {
desciption = "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<Int> = 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]
prime을 외부 범위에서 사용하면, 캡처링으로 인해 예상치 못한 결과가 나오기도 한다.
위 코드에서 시퀀스를 활용해 필터링이 지연되었고, 최종적인 prime 값(2)으로만 필터링되어 4만 제외되고 연속적인 숫자가 나오게 된다.
변수의 스코프는 좁게 가져가고 람다에서는 변수를 캡처한다는 점 잊지말자!