begaonnuri
  • 소개
  • Book
    • 이펙티브 코틀린
      • 아이템 1. 가변성을 제한하라
      • 아이템 2. 변수의 스코프를 최소화하라
      • 아이템 3. 최대한 플랫폼 타입을 사용하지 말라
      • 아이템 4. inferred 타입으로 리턴하지 말라
      • 아이템 5. 예외를 활용해 코드에 제한을 걸어라
      • 아이템 6. 사용자 정의 오류보다는 표준 오류를 사용하라
      • 아이템 7. 결과 부족이 발생할 경우 null과 Failure를 사용하라
    • 클린아키텍처
      • 1장 설계와 아키텍처란?
      • 2장 두 가지 가치에 대한 이야기
      • 3장 패러다임 개요
      • 4장 구조적 프로그래밍
      • 5장 객체 지향 프로그래밍
      • 6장 함수형 프로그래밍
      • 7장 SRP: 단일 책임 원칙
      • 8장 OCP: 개방-폐쇄 원칙
      • 9장 LSP: 리스코프 치환 원칙
      • 10장 ISP: 인터페이스 분리 원칙
      • 11장 DIP: 의존성 역전 원칙
      • 12장 컴포넌트
      • 13장 컴포넌트 응집도
      • 14장 컴포넌트 결합
      • 25장 계층과 경계
Powered by GitBook
On this page
  • 캡처링
  • 정리
  1. Book
  2. 이펙티브 코틀린

아이템 2. 변수의 스코프를 최소화하라

상태를 정의할 땐 변수와 프로퍼티의 스코프를 최소화 하는 것이 좋다.

// 나쁜 예
// 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만 동작한 결과를 반환한다.

불변으로 만들고 스코프 범위를 좁게 하면 이런 문제를 피할 수 있다.

정리

  • 변수의 스코프는 최대한 좁히는 것이 좋다.

  • var 보다는 val을 사용하는 것이 좋다.

  • 람다에서는 변수를 캡처한다.

Previous아이템 1. 가변성을 제한하라Next아이템 3. 최대한 플랫폼 타입을 사용하지 말라

Last updated 3 years ago