如何用Kotlin扩展属性实现交替返回true/false的布尔属性
Kotlin扩展属性实现交替布尔值的方案
问题背景
需要给对象添加一个布尔属性,行为要求:
- 首次获取返回
true - 第二次获取返回
false - 后续每次调用交替返回(偶数次调用返回
true,奇数次返回false)
通过类属性可以轻松实现该逻辑:
class Foo { var bar: Boolean = true get() { val value = field bar = value.not() return value } private set }
但尝试用扩展属性实现时出现报错:
var Foo.bar: Boolean = true // 报错:extension property cannot be initialized because it has no backing field get() { val value = field // 报错:Unresolved reference field bar = value.not() return value } private set
报错核心原因:Kotlin扩展属性本质是静态方法的语法糖,不会给原类添加实际成员变量,因此没有自带的 backing field,无法直接用field关键字访问或初始化值。
可行实现方案(Kotlin 1.8.0,Android环境)
方案1:用WeakHashMap维护状态(通用场景)
利用WeakHashMap存储每个对象的状态,它的键是弱引用,不会阻止对象被垃圾回收,能有效避免内存泄漏:
// 全局容器,维护每个Foo实例的布尔状态 private val barState = WeakHashMap<Foo, Boolean>() var Foo.bar: Boolean get() { // 首次获取默认返回true,后续读取存储的状态 val currentValue = barState.getOrDefault(this, true) // 切换状态并存回容器 barState[this] = !currentValue return currentValue } private set(value) { barState[this] = value }
方案2:用View的Tag存储(仅适用于View子类)
如果Foo是Android的View子类,可以利用系统自带的Tag机制存储状态:
- 先在
res/values/ids.xml中定义唯一ID:
<item name="bar_state_tag" type="id"/>
- 实现扩展属性:
var Foo.bar: Boolean get() { val currentValue = getTag(R.id.bar_state_tag) as? Boolean ?: true setTag(R.id.bar_state_tag, !currentValue) return currentValue } private set(value) { setTag(R.id.bar_state_tag, value) }
原理说明
Kotlin扩展属性不会修改原类的结构,只是提供了静态方法的语法糖包装。要实现带状态的扩展属性,必须通过外部容器(如WeakHashMap、View Tag)为每个实例单独维护状态,以此模拟类属性的backing field功能。
内容的提问来源于stack exchange,提问作者Leonardo Sibela
相关产品推荐
相关产品推荐

