假设我有以下类:

data class StuffWithParams<T>(
    val value: T,
    val params: MutableMap<String, Any> = mutableMapOf()
)

然后你可以像这样delegate additional properties to the map:

data class StuffWithParams<T>(/* */) {
    val name by params;
}

现在,我想向该类的typed instances个添加扩展属性,如下所示:

val StuffWithParams<Car>.speed: Int by params

这将导致错误显示为Unresolved reference: params.

val StuffWithParams<Car>.speed: Int by this.params

这反过来会导致错误显示为'this' is not defined in this context.


通过将其转换为一个getter属性,您可以以某种方式"绕过"此限制:

val StuffWithParams<Car>.speed: Long get() { val speed: Long by params; return speed }

...但它很难看,而且增加了所需的样板数量.

这是故意的吗?在扩展属性委托的情况下,这是不是解决this的方式中的一个错误?

有没有更优雅的方式来实现这一点?

推荐答案

您可以查看委托属性是如何转换的here,并try 将其应用于您的情况.

转换规则将生成一个存储params map 的新属性:

private val speed$delegate = params
var StuffWithParams<Car>.speed: Int
    get() = speed$delegate.getValue(this, this::speed)

但是params无法解析,因为speed$delegate的初始值设定项中没有this

另请参阅YouTrack上的this ticket.

理论上,编译器可以实现转换规则,以便也将委托属性转换为扩展:

private val StuffWithParams<Car>.speed$delegate get() = params

但请注意,这现在是一个返回this.params的Getter.如果重新分配params(尽管在您的情况下不会发生这种情况),speed$delegate的值也会改变.这可能会非常令人困惑,因为常规属性委托的行为不是这样的--它们将委托实例存储在不同的支持字段中.

您可以将这个使用params映射的"委托"思想"封装"到一个专门针对StuffWithParamsDelegate的属性委托中:

object StuffWithParamsDelegate {
    operator fun <T, U> getValue(thisRef: StuffWithParams<T>, property: KProperty<*>): U 
        = thisRef.params.getValue(thisRef, property)

    // optionally, declare setValue as well
}
val StuffWithParams<Car>.speed: Int by StuffWithParamsDelegate

或者更笼统地说:

class MapDelegate<T>(
    // use a mutable map and add setValue if you like
    val mapProperty: KProperty1<T, Map<String, Any>>
) {
    operator fun <U> getValue(thisRef: T, property: KProperty<*>): U 
        = mapProperty.get(thisRef).getValue(thisRef, property)
}
val StuffWithParams<Car>.speed: Int by MapDelegate(StuffWithParams<Car>::params)

Kotlin相关问答推荐

将带大括号和不带大括号的Lambda值赋给@Composable函数

在kotlin中匹配多个变量

为什么记得不将 StateFlow 转换为特定类型?

jlink:在合并模块和 kotlin.stdlib 中打包 kotlin.*

Eclipse:无法安装 Kotlin 插件

为什么没有remember 的 mutableStateOf 有时会起作用?

Kotlin 代码是如何编译成原生代码的?

Kotlin 方法重载

如何使用 gradle 脚本 Kotlin 构建文件构建可运行的 ShadowJar?

在 Spring Framework 5.1 中注册具有相同名称的测试 bean

将 jetpack compose 添加到现有元素

如何在 kotlin 中生成 json 对象?

Kotlin DataBinding 将静态函数传递到布局 xml

Kotlin 的 Double.toInt() 中使用了哪种方法,舍入还是截断?

(kotlin的Moshi)@Json vs@field:Json

在 sharedPref.getString 中有一个默认值有什么意义?

判断EditText是否为空kotlin android

lateinit 的 isInitialized 属性在伴随对象中不起作用

Recyclerview: listen to padding click events

如何在 Kotlin 中定义新的运算符?