티스토리 뷰

아이템2의 주제: 변수의 스코프를 최소화 하는것이 좋다

 

스코프란?

  • 어떤 요소의 스코프라고 한다면 그 요소를 볼 수 있는 컴퓨터 프로그램 영역이다.
  • 변수의 스코프라고 한다면 그 변수를 인식하고 사용할 수 있는 범위를 의미한다.
  • 코틀린에서는 기본적으로 {} 중괄호로 스코프를 만든다.

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

  • 프로퍼티 보단 지역변수를 사용하는것이 좋다.
  • 최대한 좁은 스코프를 갖도록 변수를 사용한다.

스코프 범위 좁히기의 예시

// 가장 안좋은 방법
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")
}

 

변수는 정의할때 초기화하는것이 좋다

- if, when, try-catch, Elvis 표현식을 활용하면 변수를 정의할때 초기화하는것이 편해진다.

// if
val user: User = if(hasValue) {
	getValue()
} else {
	User()
}

// when
val dayType = when (val dayOfWeek = "Monday") {
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "Weekday"
    "Saturday", "Sunday" -> "Weekend"
    else -> "Invalid day"
}

println(dayType) // 출력: Weekday

// try-catch
val result: Int = try {
    // 예외가 발생할 수 있는 코드
    val numerator = 10
    val denominator = 2
    numerator / denominator
} catch (e: ArithmeticException) {
    // 예외가 발생한 경우 처리할 코드
    println("ArithmeticException caught: ${e.message}")
    0 // 예외가 발생했을 때 반환할 값
}

println(result) // 출력: 5

// Elvis
val input: String? = null
val result: String = input ?: "Default Value"
println(result) // 출력: Default Value

 

- 여러 프로퍼티를 한번에 설정할때는 구조분해선언을 활용하는것이 좋다

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
    }

}

 

캡처링

캡처링이 뭘까요?

캡처링(=람다 캡처링): 람다 블럭 외부에서 정의된 변수를 참조하는것

람다식: 다른 함수에 매개변수로 넘길수있는 함수, 중괄호로 묶인다

fun printMessageWithPrefix(messages: Collection<String>, prefix: String) {

  var clientErrors = 0
  var serverErrors = 0

  messages.forEach {
     if(it.startsWith("4")) {
        clientErrors++          //lamda capture
     }else if(it.startsWith("5") {
        serverErrors++      //lamda capture
     }
  }

  println("$clientErrors client errors, $serverErrors server errors")
}

 

하지만 이런 캡처링때문에 문제가 생길 수 있다

아래는 소수를 구하는 코틀린 코드이다

 

fun runWithSequenceBuilder() {
    val primes: Sequence<Int> = sequence {
        var numbers = generateSequence(2) { it + 1 }
        while (true) {
            val prime = numbers.first()
            yield(prime) // sequence에 prime을 넘겨준다.
            numbers = numbers.drop(1)
                .filter { it % prime != 0 }// prime의 배수를 필터링
        }
    }
    println(primes.take(25).toList()) // sequence에 쌓인것중 25개를 List로 변환한다.
}
//[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

 

이렇게 코드를 작성하면 정상 작동한다

하지만 prime 변수를 while 밖으로 빼면 어떻게 될까

 

fun runWithSequenceBuilderButWrongScope() {
    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 }
        }
    }
    println(primes.take(25).toList())
}
//[2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]

prime 의 선언을 var로 하고 while문 밖에 선언했다

그러면 var 이니깐 while돌면서 prime값이 바뀌면서~ 잘 돌아가겠징? 하지만 아님

 

시퀀스는 게으른 연산(lazy evaluation)을 사용한다. 위 코드에서 primes 는 시퀀스로 만들어져 있다

filter, drop과 같은 중간 연산에서는 바로 연산을 수행하지 않고 종단 연산인 first를 만날때까지 연산을 누적해서 기다린다.

그래서 

1번 순환

prime = 2

filter 대기

drop 대기

 

2번순환

filter 대기

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- 참고한 사이트

https://velog.io/@kartmon61/Effective-Kotlin-%EC%BA%A1%EC%B3%90%EB%A7%81capturing%EC%9D%B4%EB%9E%80

 

Effective Kotlin - 캡쳐링(capturing)이란?

아이템 2: 변수의 스코프를 최소화하라에서 나온 내용람다 또는 익명 함수와 같은 클로저가 외부 스코프에 있는 변수를 포착하고 이를 내부에서 사용할 수 있는 기능을 말한다. 이로 인해 특정

velog.io

https://velog.io/@evergreen_tree/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0%EC%9D%80-%EB%9E%8C%EB%8B%A4%EC%8B%9D%EC%97%90%EC%84%9C-%EC%99%B8%EB%B6%80-%EB%B3%80%EC%88%98%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%B0%B8%EC%A1%B0%ED%95%A0%EA%B9%8C

 

[Kotlin] 코틀린은 람다식에서 외부 변수를 어떻게 참조할까? [람다 캡쳐링] [Lambda Capturing]

람다식 내에서 외부 변수를 변경하는 것에 대해 아무런 의문을 느끼지 않다가, 문득 궁금증이 생겼습니다. 함수를 작성하는 시점에는 람다식의 블럭 내부가 실행되지 않다가, 호출되는 시점에

velog.io

https://lovia98.github.io/blog/kotlin-lamda.html

 

코틀린에서의 람다 문법과 사용법

Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.

lovia98.github.io

https://bottom-to-top.tistory.com/64

 

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

가시성 제한 상태를 정의할 때는 변수와 프로퍼티의 스코프를 최소화하는 것이 좋다. 프로프티보다 지역 변수를 사용하는 것이 좋다. 최대한 스코프를 좁게 가지도록 변수를 사용하자. 사용되

bottom-to-top.tistory.com

https://iosroid.tistory.com/79

 

코틀린(Kotlin) Collections : 시퀀스(sequences)

코틀린(kotlin) 의 시퀀스(sequence) 를 살펴보자. 원문 https://kotlinlang.org/docs/reference/sequences.html 을 보며 정리. kotlin standard library 는 collection 과 함께 또다른 container type 인 sequences (Sequence) 를 가지고 있

iosroid.tistory.com

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함