在Kotlin中编写扩展方法很容易:
class A { }
class B {
fun A.newFunction() { ... }
}
Run Code Online (Sandbox Code Playgroud)
但有没有办法创建扩展变量?喜欢:
class B {
var A.someCounter: Int = 0
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 47
不 - 文档说明了这一点:
扩展实际上并不修改它们扩展的类.通过定义扩展,您不会将新成员插入到类中,而只是在此类的实例上使用点符号使新函数可调用.
和
请注意,由于扩展实际上并未将成员插入到类中,因此扩展属性没有有效的方法来获得支持字段.这就是扩展属性不允许初始值设定项的原因.他们的行为只能通过明确提供getter/setter来定义.
考虑扩展函数/属性只是用于调用静态函数和传入值的语法糖,这有助于明确这一点.
Mic*_*ael 41
您可以使用重写的getter和setter创建扩展属性:
var A.someProperty: Int
get() = /* return something */
set(value) { /* do something */ }
Run Code Online (Sandbox Code Playgroud)
但是您无法使用支持字段创建扩展属性,因为您无法将字段添加到现有类.
hot*_*key 18
有没有办法与支持字段添加扩展属性上课,因为扩展实际上并不修改类.
您只能使用自定义getter(和setter for var)或委托属性定义扩展属性.
使用标识,而不是equals()/ hashCode(),实际存储每个对象的值,就像IdentityHashMap;
不防止密钥对象被垃圾收集(使用弱引用),就像这样WeakHashMap做.
不幸的是,WeakIdentityHashMap在JDK中没有,所以你必须实现自己的(或采取完整的实现).
然后,基于此映射,您可以创建满足属性委托要求的委托类.这是一个非线程安全实现的示例:
class FieldProperty<R, T : Any>(
val initializer: (R) -> T = { throw IllegalStateException("Not initialized.") }
) {
private val map = WeakIdentityHashMap<R, T>()
operator fun getValue(thisRef: R, property: KProperty<*>): T =
map[thisRef] ?: setValue(thisRef, property, initializer(thisRef))
operator fun setValue(thisRef: R, property: KProperty<*>, value: T): T {
map[thisRef] = value
return value
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
var Int.tag: String by FieldProperty { "$it" }
fun main(args: Array<String>) {
val x = 0
println(x.tag) // 0
val z = 1
println(z.tag) // 1
x.tag = "my tag"
z.tag = x.tag
println(z.tag) // my tag
}
Run Code Online (Sandbox Code Playgroud)
在类中定义时,映射可以独立存储在类的实例中,也可以存储在共享的委托对象中:
private val bATag = FieldProperty<Int, String> { "$it" }
class B() {
var A.someCounter: Int by FieldProperty { 0 } // independent for each instance of B
var A.tag: String by bATag // shared between the instances, but usable only inside B
}
Run Code Online (Sandbox Code Playgroud)
此外,请注意,由于装箱,不保证 Java的原始类型的身份.
我怀疑这个解决方案的性能明显比常规字段差,很可能接近正常Map,但这需要进一步测试.
有关可空属性支持和线程安全实现,请参阅此处.
您不能添加字段,但可以添加一个属性,该属性委托给对象的其他属性/方法以实现其访问器.例如,假设您要向类中添加secondsSinceEpoch属性,则java.util.Date可以编写
var Date.secondsSinceEpoch: Long
get() = this.time / 1000
set(value) {
this.time = value * 1000
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14785 次 |
| 最近记录: |