Kotlin - 如何通过地图使用自定义名称进行属性委托?

时间:2016-04-13 15:00:01

标签: properties delegates kotlin delegation

我正试图让我的头围绕属性代表,我有一个有趣的用例。是否有可能有这样的事情:

class MyClass {
    val properties = mutableMapOf<String, Any>()
    val fontSize: Any by MapDelegate(properties, "font-size")
}

这样我就可以使用地图作为代理存储fontSize,但使用自定义键(即“font-size”)。

特定用例,用于存储CSS属性标记之类的东西,可以通过变量(fontSize)访问,以便在代码中使用,但在迭代地图时可以正确呈现(font-size: 18px;

1 个答案:

答案 0 :(得分:8)

the delegated properties上的文档是有关该主题的良好信息来源。它可能比以下示例读取时间长一些:

fun <T, TValue> T.map(properties: MutableMap<String, TValue>, key: String): ReadOnlyProperty<T, TValue> {
    return object : ReadOnlyProperty<T, TValue> {
        override fun getValue(thisRef: T, property: KProperty<*>) = properties[key]!!
    }
}

class MyClass {
    val properties = mutableMapOf<String, Any>()
    val fontSize: Any by map(properties, "font-size")
}

您可以稍微放松一下,避免键入CSS属性名称,方法是将Kotlin属性名称转换为CSS属性,如下所示:

fun <T, TValue> map(properties: Map<String, TValue>, naming:(String)->String): ReadOnlyProperty<T, TValue?> {
    return object : ReadOnlyProperty<T, TValue?> {
        override fun getValue(thisRef: T, property: KProperty<*>) = properties[naming(property.name)]
    }
}

object CamelToHyphen : (String)->String {
    override fun invoke(camelCase: String): String {
        return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, camelCase)
    }
}

fun <T, TValue> T.cssProperties(properties: Map<String,TValue>) = map(properties, CamelToHyphen)

class MyClass {
    val properties = mutableMapOf<String, Any>()
    val fontSize: Any? by cssProperties(properties)
}

以上示例使用了Guava的CaseFormat

如果你想拥有可变属性,你的委托必须实现setter方法:

fun <T, TValue> map(properties: MutableMap<String, TValue?>, naming: (String) -> String): ReadWriteProperty<T, TValue?> {
    return object : ReadWriteProperty<T, TValue?> {
        override fun setValue(thisRef: T, property: KProperty<*>, value: TValue?) {
            properties[naming(property.name)] = value
        }

        override fun getValue(thisRef: T, property: KProperty<*>) = properties[naming(property.name)]
    }
}