fun <T, R> with(receiver: T, block: T.() -> R): R
이렇게 receiver로 객체를 입력받으면 it이나 this등 키워드 없이 객체의 속성을 참조하거나 변경할 수 있습니다.
val person = Person("heetae",25)
with(person) {
println(name)
println(age)
// 자신을 참조해야 하는 경우에는 this을 사용합니다.
}
따라서 with는 non-null 객체를 이용할 때만 사용할 수 있고 아무런 리턴을 할 수 없기 때문에 별다른 반환값이 필요하지 않을 때 사용합니다.
즉, 객체의 함수나 속성을 여러 번 호출할 때 코드들을 그룹핑하는 용도로 활용할 수 있습니다.
반면 run을 보면
fun <T, R> T.run(block : T.() -> R): R
with 와 다른 점이라면 T의 확장함수로 선언되어 있다는 점입니다. 확장함수이기 때문에 with와 다르게 Safe Call을 붙인다면 null 객체가 들어와도 non-null 검사를 하고 실행할 수 있습니다.
val person = Person("heetae",25)
val ageNextYear = person.run {
**age // Return
}
println("$ageNextYear")
// 결과 : 100
또한 마지막 실행문의 결과를 반환하게 됩니다. 따라서 객체의 특성이나 메서드 등을 활용하여 어떤 값을 계산할 필요가 있거나 여러 개의 지역변수 범위를 제한하고자 할 때 사용합니다.
그리고 두 번째 run 선언방식은 다음과 같습니다.
fun <R> run(block: () -> R ) : R
이것은 확장함수가 아니고 블록에 입력값도 없습니다. 객체 속성을 이용하려는 상황에 사용되는 함수가 아니고 어떤 객체를 생성하기 위한 실행문들을 하나로 묶어 리더빌리티를 높이는 역할을 수행합니다.
val person = run{
val name = "heetae"
val age = 25
Person(name, age) // return
}
이러면, Person(name="heetae", age=25) 객체가 person 에 담기게 됩니다.