29. 委托属性

作者: 厚土火焱 | 来源:发表于2017-11-24 22:25 被阅读26次

    很多常见属性不是简单的数据,需要每次去手动实现。如果为了方便,可以只写一个类,把他们放进去反复使用是最好的选择。
    这里我们使用委托属性。
    先看一个例子

    class Delegate{
        val Hello by lazy{
            "HelloWorld"
        }
    }
    

    当我们调用这个 Hello 的时候,会返回一个字符串 HelloWorld。这个 Hello 只会在第一次调用的时候才赋值。它是使用了 lazy 来实现这个延迟的操作。而观察 lazy 的源码,我们能发现,它有一个 getValue 的函数。

    public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
    

    所以 lazy 能够实现取值。
    调用方式如下

        val delegate = Delegate()
        println(delegate.Hello)
    

    而这样的委托,我们也可以自己写出来。

    class X {
        private var value:String? = ""
        operator fun getValue(thisRef: Any?, property: KProperty<*>):String{
            println("getValue: $thisRef -> ${property.name}")
            return value?:""
        }
        operator fun setValue(thisRef: Any?, property: KProperty<*>, value:String){
            println("getValue: $thisRef -> ${property.name} = $value")
            this.value = value
        }
    
    }
    

    我们建立了一个类,叫 X。实现取值和赋值的操作。
    为了看到细节,在赋值和取值的操作代码中,都加入了打印语句。
    代码结构是不是很熟悉,是的,我是从 lazy 中抄过来的。不过,X 只支持 String 类型的读写。
    然后,在类 Delegate 中增加两个属性。

        val Hello2 by X()
        var Hello3 by X()
    

    一个常量、一个变量。
    常量 Hello2 只能 getValue;变量 Hello3 可以getValue和setValue。
    在 main 中我们直接输出,并且在给 Hello3 赋值,看看会发生什么。

        val delegate = Delegate()
        println(delegate.Hello)
        println(delegate.Hello2)
        println(delegate.Hello3)
        delegate.Hello3 = "顺"
    

    这是完整的运行结果

    HelloWorld
    getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello2
    
    getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello3
    
    getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello3 = 顺
    

    尤其注意 Hello3,取值和赋值执行的是不同的函数方法。
    由此可看出,虽然 delegate 的属性是 Hello2 Hello3,但是真正替代它们起作用的是 X。它的核心实现就是 getValue 和 setValue。

    相关文章

      网友评论

        本文标题:29. 委托属性

        本文链接:https://www.haomeiwen.com/subject/uzfqbxtx.html