티스토리 뷰
728x90
위임 프로퍼티
1. 표준 위임
- lazy()
- LazyThreadSafeyMode 이넘 상수 값
- SYNCHRONIZED: 항상 하나의 스레드에 의해서만 초기화되도록 보장한다. (default)
- PUBLICATION: 초기화 함수가 여러번 호출될 수 있지만 가장 처음 도착하는 결과가 프로퍼티 값이 된다.
- NONE: 프로퍼티 접근을 동기화하지 않는다. (가장 빠르며 한 스레드에서만 불린다고 확신할 수 있는 경우)
- LazyThreadSafeyMode 이넘 상수 값
val value1 by lazy {
println("Initializing value")
123
}
val value2 by lazy(LazyThreadSafeyMode.PUBLICATION) {
println("Initializing value")
123
}
-
- value1은 default로 SYNCHRONIZED 모드이기 떄문에 메시지가 최대 한번만 출력된다.
- value2는 프로퍼티 값은 한번만 변경되지만 여러 스레드가 값을 초기화하려고 시도하면서 메시지가 여러번 출력될 수 있다.
- notNull()
var text: String by notNull()
fun main() {
println(text) // error
text = ""
println(text)
}
- 초기화를 미루면서 널이 아닌 프로퍼티를 정의할 수 있다.
- lateinit과 같은 기능이지만, lateinit은 primitive type에 사용될 수 없고 notNull()은 가능하다.
- observable()
var name: String by observable("John") { _, old, new ->
println("Name changed: $old to $new")
}
fun main() {
name = "Vincent" // Name changed: John to Vincent
name = "Harry" // Name changed: Vincent to Harry
}
-
- 프로퍼티 값이 변경될 때 통지를 받을 수 있다.
- 초깃값과 람다를 인자를 받는다.
- 이전 값과 새 값이 같더라도, 대입 연산자를 통해 값을 write하면 통지가 온다.
- vetoable()
var pwd: String by vetoable("password") { _, old, new ->
if(new.length < 8) {
println("Password should be at least 8 characters long")
false
}
else {
println("Password is Ok")
true
}
}
fun main() {
pwd = "pAsSwOrD" // Password is Ok
println(pwd) // pAsSwOrD
pwd = "qwerty" // Password should be at least 8 characters long
println(pwd) // pAsSwOrD
}
-
- 초깃값과 Boolean을 반환하는 람다를 인자로 받는다.
- 프로퍼티 값을 변경하기 직전 람다가 호출되며, 람다가 true를 반환하면 변경되고 false를 반환하면 변경되지 않는다.
- Map 위임 객체
class MapDelegate(data: Map<String, Any?>) {
// 프로퍼티 이름: key, 위임 객체: Map
val str: String by data
val i: Int by data
}
fun main() {
val mapDelegate = MapDelegate(mapOf("str" to "Hello", "i" to 10))
println(mapDelegate.str) // Hello
println(mapDelegate.i) // 10
}
- 프로퍼티의 이름을 키로 사용하고, 위임 객체를 Map으로 하면 프로퍼티에 값이 저장된다.
2. 커스텀 위임
- 커스텀 위임을 만들기 위해서는 위임 클래스에 함수나 연산자 함수를 정의해야 한다.
- getValue()
class Delegate(str: String) {
var value: String = str
operator fun getValue(receiver: Nothing?, property: KProperty<*>): String {
return value
}
}
fun main() {
val p: String by Delegate("Hello")
println(p)
}
- val/var 위임 프로퍼티의 값을 읽을 때 호출되는 함수
- 반환 타입: 위임 프로퍼티의 타입 또는 하위 타입
- 파라미터
- receiver: receiver와 같은 타입이거나 상위 타입
- property: 위임 프로퍼티를 표현하는 KProperty<*> 리플렉션
- setValue()
class Delegate {
lateinit var value: String
operator fun getValue(receiver: Nothing?, property: KProperty<*>): String {
return value
}
operator fun setValue(receiver: Nothing?, property: KProperty<*>, newValue: String) {
value = newValue
}
}
fun main() {
var p: String by Delegate()
p = "Hello"
println(p)
}
- var 위임 프로퍼티에 값을 저장할 때 호출되는 함수
- 반환 타입: Unit
- 파라미터
- receiver
- property
- newValue: 프로퍼티에 저장할 새 값. 프로퍼티와 같은 타입이거나 상위 타입
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
- ReadOnlyProperty/ReadWriteProperty 인터페이스를 사용해 커스텀 위임을 정의할 수 있다.
- provideDelegate()
class Delegate {
operator fun provideDelegate(receiver: Nothing?, property: KProperty<*>): Delegate {
// 위임 객체 제어 로직
return Delegate()
}
operator fun getValue(...) { ... }
}
fun main() {
val p: String by Delegate()
}
- 위임 객체의 인스턴스화를 제어할 수 있다.
- 반환 타입: 실제 위임 객체
3. 위임 표현
class Delegate {
operator fun getValue(...) { ... }
operator fun setValue(...) { ... }
}
fun main() {
private val delegate = Delegate() // 컴파일러가 생성한 보조 프로퍼티
var p: String
set(value: String) = delegate.setValue(..., value)
get() = delegate.getValue(...)
}
- 내부적으로 컴파일러는 위임 프로퍼티의 보조 프로퍼티를 만들고, 위임 프로퍼티의 게터와 세터에 getValue(), setValue()를 넣는다.
- getDelegate()
val p: String by lazy { "Hello" }
fun main() {
val delegate = ::p
.apply { isAccessible = true }
.getDelegate() ?: return
println(delegate::class.qualifiedName) // kotlin.SynchronizedLazyImpl
}
-
- KProperty의 멤버 함수이며 위임 값을 얻을 수 있다.
- getExtensionDelegate()
class Foo
val Foo.p: String by lazy { "Hello" }
fun main() {
val delegate = Foo::p
.apply { isAccessible = true }
.getExtensionDelegate() ?: return
println(delegate::class.qualifiedName) // kotlin.SynchronizedLazyImpl
}
-
- 확장 프로퍼티의 위임 값을 얻을 수 있다.
728x90
'kotlin' 카테고리의 다른 글
[kotlin/코틀린] 코루틴 흐름 제어 (Job, 타임아웃, 디스패처, 예외 처리) (0) | 2023.07.20 |
---|---|
[kotlin/코틀린] 코루틴 기초 (suspend 함수, 코루틴 빌더, 문맥, 범위) (0) | 2023.07.19 |
[kotlin/코틀린] 연산자 오버로딩 (0) | 2023.07.19 |
[kotlin/코틀린] 리플렉션 (0) | 2023.07.19 |
[kotlin/코틀린] 어노테이션 (0) | 2023.07.19 |