簡體   English   中英

在Kotlin訪問屬性委托

[英]Access property delegate in Kotlin

Kotlin委托了屬性,這是一個非常好的功能。 但有時候get()set()方法還不夠。 假設我想懶洋洋地創建一個Closeable對象並稍后關閉它。 以下是如何實現此類委托屬性的示例:

fun <T : Closeable> closeableLazy(initializer: () -> T) =
        CloseableLazyVal(initializer)

class CloseableLazyVal<T : Closeable>(
    private val initializer: () -> T
) : ReadOnlyProperty<Any?, T> {

    private var value: T? = null

    override fun get(thisRef: Any?, desc: PropertyMetadata): T {
        if (value == null) {
            value = initializer()
        }
        return value
    }

    fun close() {
        value?.close()
    }
}

這就是我想用它的方式:

private val stream by closeableLazy { FileOutputStream("/path/to/file") }

fun writeBytes(bytes: ByteArray) {
    stream.write(bytes)
}

override fun close() {
    stream::delegate.close() // This line will not compile
}

不幸的是,這種方法不起作用,因為Kotlin似乎不允許直接訪問屬性委托。 有什么辦法可以做我想要的嗎? 或者是否有任何計划將此類功能添加到Kotlin,因為它將是一個如此簡潔的功能。

好的,所以我提出了以下解決方案:

fun <T : Closeable> closeableLazy(initializer: () -> T) =
        CloseableLazyVal(initializer)

class CloseableLazyVal<T : Closeable>(
        private val initializer: () -> T
) : ReadOnlyProperty<CloseableDelegateHost, T> {

    private var value: T? = null

    override fun get(thisRef: CloseableDelegateHost, desc: PropertyMetadata): T {
        if (value == null) {
            value = initializer()
            thisRef.registerCloseable(value!!)
        }
        return value!!
    }

}

interface CloseableDelegateHost : Closeable {
    fun registerCloseable(prop : Closeable)
}

class ClosableDelegateHostImpl : CloseableDelegateHost {

    val closeables = arrayListOf<Closeable>()

    override fun registerCloseable(prop: Closeable) {
        closeables.add(prop)
    }

    override fun close() = closeables.forEach { it.close() }
}

class Foo : CloseableDelegateHost by ClosableDelegateHostImpl() {
    private val stream by closeableLazy { FileOutputStream("/path/to/file") }

    fun writeBytes(bytes: ByteArray) {
        stream.write(bytes)
    }

}

請注意,屬性的get方法有一個參數thisRef 我要求它繼承自CloseableDelegateHost ,它將在關閉時關閉任何已注冊的Closeable 為了簡化實現,我將此接口委托給一個簡單的基於列表的實現。

UPDATE (從注釋中復制):我意識到,您可以將委托聲明為單獨的屬性,然后將第二個屬性委托給它。 這樣您就可以輕松訪問委托本身。

private val streamDelegate = closeableLazy { FileOutputStream("/path/to/file") }
private val stream by streamDelegate

fun writeBytes(bytes: ByteArray) {
    stream.write(bytes)
}

override fun close() {
    streamDelegate.close()
}

在Kotlin 1.1中(從beta 2開始),可以從屬性中檢索代理,因此您現在可以編寫代碼

override fun close() {
    (::stream.apply { isAccessible = true }.getDelegate() 
        as CloseableLazyVal<*>).close()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM