我有一个包含可变值的 Kotlin 类。
class StringWrapper(
var value: String = ""
) {
override fun toString(): String = value
}
我使用此包装器作为自定义数据持有者类中的属性
class DataHolder {
val name = StringWrapper()
override fun toString(): String = "Data(name=$name)"
}
我想让为 StringWrapper 的内容赋值变得更容易
val dataAlpha = DataHolder()
// the '.value' is unnecessary noise
dataAlpha.name.value = "alpha"
// I want to directly assign a string value, but I get an error
dataAlpha.name = "alpha" // ERROR Type mismatch.
// Required: StringWrapper
// Found: String
我还希望能够更轻松地将一个 StringWrapper
复制到另一个。
val dataAlpha = DataHolder()
dataAlpha.name = "alpha"
val dataAlphaCopy = DataHolder()
// I want to directly assign the value of `dataAlpha.name.value` into `dataAlphaCopy.name.value`
dataAlphaCopy.name = dataAlpha.name // ERROR Val cannot be reassigned
据我了解 Gradle 8.1 has a new experimental feature在 Kotlin DSL 中,它可以满足我的需求。如何在我自己的库中引入相同的赋值运算符?
我尝试查看 operator overloading docs ,但没有引用赋值运算符。
有一个KEEP language proposal for introducing such a feature ,但是it was closed .
我使用的是 Kotlin 1.8.20
最佳答案
有一个新的 Kotlin (v1.8.0) 编译器插件,可用于提供运算符加载。
尚未公布,但已可供使用。它在 Kotlin source code here 中。它与 Gradle 在 Gradle version 8.1 的 Kotlin DSL 中使用的插件相同。
IntelliJ 中的支持可能有限 - 请确保您使用的是最新版本。
应用 Kotlin 赋值编译器插件
Kotlin 分配插件可以像其他 Kotlin 编译器插件一样应用。
在 Gradle 项目中,可以使用 a simple Gradle plugin 来应用它。
我不熟悉使用 Maven、Ant 或 CLI 编译 Kotlin - 但请查看 the other Kotlin compiler plugin instructions for similar instructions 。
ephemient has shared CLI instructions on Slack
$KOTLIN_HOME/bin/kotlinc-jvm -Xplugin=$KOTLIN_HOME/lib/assignment-compiler-plugin.jar -P plugin:org.jetbrains.kotlin.assignment:annotation=fqdn.SupportsKotlinAssignmentOverloading ...
(you can see all the strings in https://github.com/JetBrains/kotlin/blob/master/plugins/assign-plugin/assign-plugin.common/src/org/jetbrains/kotlin/assignment/plugin/AssignmentPluginNames.kt)
设置赋值重载
首先在您的项目中创建注释
package my.project
/** Denotes types that will be processed by the Kotlin Assignment plugin */
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class KotlinAssignmentOverloadTarget
然后在 Gradle 中应用插件,并将其配置为使用您的注释
plugins {
kotlin("plugin.assignment") version "1.8.10"
}
assignment {
annotation("my.project.KotlinAssignmentOverloadTarget")
}
然后在代码中将注释应用于 StringWrapper
。
@KotlinAssignmentOverloadTarget
class StringWrapper(
var value: String = ""
) {
override fun toString(): String = value
}
我建议通常应将注释应用于包含一个(或可能多个)可变值的“包装器”类。它也可以应用于其他类似类实现的接口(interface)(which is what Gradle does)。
编写赋值运算符
应用编译器插件并设置注释后,您就可以开始编写重载运算符。
- 它们必须命名为
分配
并返回Unit
。 - 它们必须是 member functions 或 extension functions 。
- 请注意,它们不需要需要通常用于 operator overloading 的
operator
修饰符。
@KotlinAssignmentOverloadTarget
class StringWrapper(
var value: String = ""
) {
// member function
/** Provides overloaded setter for setting the value of [value] using an assignment syntax */
fun assign(value: String) {
this.value = value
}
}
// extension function
/** Provides overloaded setter for setting the value of [value] using an assignment syntax */
fun StringWrapper.assign(value: StringWrapper) {
this.value = value.value
}
使用赋值运算符
您现在可以直接将字符串分配给 name
属性
val dataAlpha = DataHolder()
dataAlpha.name = "alpha"
println(dataAlpha) // prints: Data(name=alpha)
此外,使用扩展函数将一个 StringWrapper
分配给另一个。
val dataAlphaCopy = DataHolder()
dataAlphaCopy.name = dataAlpha.name
println(dataAlphaCopy) // prints: Data(name=alpha)
限制
属性不能可变
当 StringWrapper
类型的属性为 var
时,运算符重载将不起作用。它们必须是 val
。
class MutableDataHolder {
var name = StringWrapper()
}
fun main() {
val dataAlpha = MutableDataHolder()
// no overload operator is generated, because name is a 'var'
dataAlpha.name = "alpha" // ERROR Type mismatch.
}
赋值重载仅适用于成员属性
请记住,赋值重载仅在属性为 member properties 时有效。
因此,当 StringWrapper
值不是类属性时,赋值重载器将不起作用。
val nameValue = StringWrapper()
nameValue = "123" // ERROR Val cannot be reassigned, and Type mismatch
手动调用assign()
函数,或者创建一个带有属性的类。使用 object expression 也可以。
val nameValue = StringWrapper()
// manually call the 'assign' function
nameValue.assign("123")
val values = object {
val name = StringWrapper()
}
values.name = "123" // 'name' is a member property, so the assignment overload works
关于kotlin - 如何在 Kotlin 中定义自定义赋值运算符重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76022932/