1) Scope Function ( 범위 지정 함수 )

1-1) 범위 지정 함수

코틀린 표준 라이브러리에서 제공하는 확장 함수

1-2) 목적

간결성, 명료성, 유지보수 용이성 향상

1-3) 정의

객체의 컨텍스트 내에서 실행 가능한 코드 블럭을 만드는 함수

호출 시, 임시 범위가 생성되며, 이 범위 안에서는 이름 없이 객체에 접근 가능

  • context : 문맥, 맥락, 전후 사정

1-4) 예

사람이 풍선을 크게 분다.

사람: 객체 풍선: 실행 가능한 코드 블럭

풍선 안에서는 이 사람이 가지고 있는 모든 정보를 사용할 수 있다.

  1. 사람으로부터 풍선을 생성하거나
  2. 사람이 함수의 인자로 들어가는 방식, 이렇게 2가지가 있음

2) 수신 객체

2-1) 수신 객체 ( receiver )

확장 함수가 호출되는 대상이 되는 값 (객체)

예) 사람

 

2-2) 수신 객체 지정 람다 ( lambda with receiver )

수신 객체를 명시하지 않고, 람다의 본문 안에서 해당 객체의 메서드를 호출할 수 있게 하는 것

예) 풍선

 

 

2-3) 차이점

수신 객체 접근 방법 : this, it Return 값 : 수신 객체, 마지막 행 ( lambda result )

수신객체 확장함수로 호출 함수의 연산자

this ( 생략가능) apply ruin with
it ( 생략가능 ) also let -
return 수신객체 람다 식의 마지막 행 람다 식의 마지막 행

let : null 체크를 해야할 때, 지역 변수를 명시적으로 표현해야 할 때

run : 객체를 초기화하고 리턴 값이 있을 때

apply : 객체 초기화

also : 수신 객체를 명시적으로 사용하고 싶을 때, 로그를 남길 때

with : 객체 초기화, 람다 리턴 값이 필요 없을 때

 

3) 실습으로 알아보기

처음 접하니 위 내용이 이해가 안 되었고 강사님의 말이 너무 빨랐다. 실습으로 이해해보자.

3-1) User 클래스 선언

먼저 User 클래스를 선언한다.

class User(
    val name : String,
    val age : Int,
    val gender : Boolean, // true: female, false: male

)

 

 

3-2) let

fun main() {
    // 확장 함수의 종류
    // let, run, apply, also, with

    // 1) let
    val a = 3
    a.let{ }

    val user = User("김주연", 10, true)
    val age = user.let {
        user.age
    }
    println(age) // 10
    

}
     수신객체.let { user ->
        코드 블럭
        마지막줄 // return
     }

 

it : 기본값

local variable it을 user → 로 명시할 수 있음

null safe 시 사용함

    // 1) let
    var user : User? = User("김주연", 10, true)
    val age = user?.let {
        it.age
    }
    println(age)

    user = null
    println(age)

 

 

3-3) run

객체를 초기화할 때 많이 사용 함수를 오버라이드할 때

    // 2) run
    val kid = User("아이", 4, false)
    
    
    val kid_age = kid.run {
        age
        // this.age
    }
    println(kid_age) // 4
    
    
    val kid_name = kid.run {
        name
    }
    println(kid_name) // com.example.kotlin.User@7c30a502

수신객체.run { this ->
    
    마지막줄 // 리턴값
    }

let 과 run 의 차이는 수신 객체를 받는 방식의 차이

it 이냐 this 이냐? this 는 생략가능

 

 

3-4) apply

apply 에 대해 설명하기 위해서 클래스에 멤버변수 하나 더 추가

var has_glasses : Boolean

class User(
    val name : String,
    val age : Int,
    val gender : Boolean, // true: female, false: male
    var has_glasses : Boolean = true,
)
    // 3) apply
    val female = User("슬기", 20, true, true)
    val female_value = female.apply {
        has_glasses = false
    }
    println(female_value.has_glasses) // false

run 과의 공통점) 수신객체를 this 로 받는다

run 과의 차이점 ) run : 람다 식 리턴 apply : 자기자신 리턴

     수신객체.apply {

     }
     return 값이 수신 객체

 

 

3-5) also

    // 4) also
    val male = User("진현", 17, false, true)
    
    val male_value = male.also { user ->
        user.name
        user.has_glasses = false
    }
    println(male_value.has_glasses) // false
     수신객체.also { it -> // it 대신 local variable 로 선언 가능

     } // return 수신객체 ( 자기자신 )

apply 와 also 의 차이점 apply : this (생략가능) 로 수신 객체를 받음 also : it ( 또는 local variable ) 로 수신 객체를 받음

코틀린 공식 문서에서 추천 apply : 초기화 작업

also : 수신 객체에 대한 내용을 확인하기 위해 로그 찍을 때

    val male = User("진현", 17, false, true)
    val male_value = male.also {
        println(it.name)
    }

 

 

3-6) with

with 는 확장함수는 아님

    // 5) with
    // 확장 함수는 아님
    val result = with(male) {
        has_glasses = false
        "값 초기화 성공"
    }
    println(result) // 값 초기화 성공

함수의 argument(인자) 들어가서 뒤의 코드 블럭에서 사용됨

    with(수신객체) { // this
        코드블럭
        마지막 줄이 리턴값
    }

처음부터 적절한 확장함수를 사용하려 하기 보다는 확장 함수 하나씩 사용해보는 것을 추천

 

 

4) 전체코드

fun main() {
    // 확장 함수의 종류
    // let, run, apply, also, with

    // 1) let
    var user : User? = User("김주연", 10, true)
    val age = user?.let {
        it.age
    }

    // 2) run
    val kid = User("아이", 4, false)
    val kid_age = kid.run {
        age
        // this.age
    }
    println(kid_age)

    // 3) apply
    val female = User("슬기", 20, true, true)
    val female_value = female.apply {
        has_glasses = false
    }
    println(female_value.has_glasses) // false

    // 4) also
    val male = User("진현", 17, false, true)
    val male_value = male.also {
        println(it.name)
    }

    // 5) with
    // 확장 함수는 아님
    val result = with(male) {
        has_glasses = false
        "값 초기화 성공"
    }
    println(result) // 값 초기화 성공

}

class User(
    val name : String,
    val age : Int,
    val gender : Boolean, // true: female, false: male
    var has_glasses : Boolean = true,
)

+ Recent posts