如何为 kotlin 委托属性使用不同的类型

Posted

技术标签:

【中文标题】如何为 kotlin 委托属性使用不同的类型【英文标题】:How to use different types for kotlin delegation properties 【发布时间】:2021-10-18 12:18:19 【问题描述】:

我尝试编写一个 LiveData 类,它将原始(可为空的)值包装到一个 Result 类中,清楚地表明是否有一个值( Result.Success )或不是(Result.Failure)。 在整个应用程序中,我使用这个类来区分加载某些文件的过程是否成功。因此,出于这个原因,我决定在我的 LiveData 子类中也使用它,即使命名并不合理。为了让生活更轻松,有一些流畅的辅助方法可以在不同的情况下执行代码。

sealed class Result<out T: Any> 
    data class Success<out T: Any>(val value: T): Result<T>()
    object Failure: Result<Nothing>()

    fun onSuccess(block: (T) -> Unit): Result<T> 
        if(this is Success) 
            block(value)
        

        return this
    

    fun onFailure(block: () -> Unit): Result<T> 
        if(this is Failure) 
            block()
        

        return this
    

    fun handle(onSuccess: (T) -> Unit, onFailure: () -> Unit): Result<T> 
        if(this is Success) 
            onSuccess(value)
         else 
            onFailure()
        

        return this
    

所以我需要能够设置 T 类型的值,但获取 包装结果-对象。 简单的方法是使用像 setValue(value: T) 这样的函数来更改值,使用 getValue(): Result 来安全地接收值。但我想使用 kotlin 的委托属性 ( SafeMutableLiveDataDelegation ) 来做到这一点。


abstract class SafeLiveData<T: Any> 
    abstract val value: Result<T>


class SafeMutableLiveData<T: Any>: SafeLiveData<T>() 
    private val mutableValue = MutableLiveData<T>()
    override var value by SafeMutableLiveDataDelegation(mutableValue)

    operator fun getValue(thisRef: Any?, property: KProperty<*>): SafeMutableLiveData<T> 
        return this
    

    fun ifAvailable(block: (T) -> Unit): SafeMutableLiveData<T> 
        value.onSuccess(block)

        return this
    

    fun ifNotAvailable(block: () -> Unit): SafeMutableLiveData<T> 
        value.onFailure(block)

        return this
    

    fun handle(ifAvailable: (T) -> Unit, ifNotAvailable: () -> Unit): SafeMutableLiveData<T> 
        value.handle(ifAvailable, ifNotAvailable)

        return this
    

只使用只读访问(override val value by...)一切都很好,但是如何创建一个可以这样做的委托类呢?类似的东西:

private class SafeMutableLiveDataDelegation<T: Any>(private val mutableLiveData: MutableLiveData<T>) 
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Result<T> 
        return  if(mutableLiveData.value != null)
            Result.Success(mutableLiveData.value!!)
        else
            Result.Failure
    


    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) 
        mutableLiveData.value = value
    

【问题讨论】:

【参考方案1】:

嗯,你不能。 requirements 包括:

getValue() 必须返回与属性(或其子类型)相同的类型。

value [setValue 的参数] 必须与属性(或其超类型)属于同一类型。

并且没有类型 P 可以用于属性,这样:Result&lt;T&gt;PP 的子类型;而TPP 的超类型。

但是您可以只添加一个采用 T 的方法,而不是使其成为 setter:

// inside SafeMutableLiveData
fun set(value: T) 
    mutableLiveData.value = Result.Success(value)

【讨论】:

以上是关于如何为 kotlin 委托属性使用不同的类型的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin学习与实践 Kotlin的可控性

Kotlin 委托

kotlin委托工厂map存储属性值

Kotlin基础初探

Kotlin小知识之泛型和委托

Kotlin 对象枚举委托