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