Operator overloading 超载+;和+;=运营商;“数字类”;
我想为封装simpleOperator overloading 超载+;和+;=运营商;“数字类”;,operator-overloading,kotlin,extension-function,Operator Overloading,Kotlin,Extension Function,我想为封装simpleNumbers的类创建扩展函数。例如DoubleProperty。我遇到的问题是,我不能同时重载+和+=操作符 我不想创建通过以下测试的行为: class DoublePropertyTest { lateinit var doubleProperty: DoubleProperty @Before fun initialize() { doubleProperty = SimpleDoubleProperty(0.1) }
Number
s的类创建扩展函数。例如DoubleProperty
。我遇到的问题是,我不能同时重载+
和+=
操作符
我不想创建通过以下测试的行为:
class DoublePropertyTest {
lateinit var doubleProperty: DoubleProperty
@Before
fun initialize() {
doubleProperty = SimpleDoubleProperty(0.1)
}
@Test
fun plus() {
val someProperty = doubleProperty + 1.5
assertEquals(someProperty.value, 1.6, 0.001)
}
@Test
fun plusAssign() {
val someProperty = doubleProperty
doubleProperty += 1.5 //error if + and += are overloaded
assert(someProperty === doubleProperty) //fails with only + overloaded
assertEquals(doubleProperty.value, 1.6, 0.001)
}
}
可以使用以下扩展功能来实现:
operator fun ObservableDoubleValue.plus(number: Number): DoubleProperty
= SimpleDoubleProperty(get() + number.toDouble())
operator fun WritableDoubleValue.plusAssign(number: Number)
= set(get() + number.toDouble())
问题是,如果+
过负荷,那么+=
也不能过载:
Assignment operators ambiguity. All these functions match.
- public operator fun ObservableDoubleValue.plus(number: Number): DoubleProperty
- public operator fun WritableDoubleValue.plusAssign(number: Number): Unit
如果我只重载+
操作符,则在+=
操作上返回一个新的DoubleProperty
对象,而不是初始对象
有没有办法绕过这个限制?如果您的类是
DoubleProperty
,您可以将plus
和plusaSign
作为其方法,以解决任何歧义。您不能同时重载+
和+=
。使其中一个过载
当您在代码中写入+=时,理论上,两者都加上plusaSign函数
可以调用(见图7.2)。如果是这种情况,并且两个函数都已定义和
如果适用,编译器将报告错误
我从《科特林在行动》一书中复制/粘贴 Kotlin中奇怪的+=
运算符
您可以在kotlin中重载plus
运算符和plusaSign
运算符,但必须遵循kotlin的规则来解决奇怪的+=
冲突
plus
操作符引入类的不可变结构,这意味着类之外的任何类都不能编辑其内部数据
plusAssign
运算符引入类的可变结构,这意味着其内部数据可以在任何地方编辑
stdlib
中为集合
和映射
类做了如下工作:
operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T>
// ^--- immutable structure
operator fun <T> MutableCollection<in T>.plusAssign(elements: Iterable<T>)
// ^--- mutable structure
如果列表是可变的MutableCollection
,则必须定义一个不可变的val
变量,然后使用plusAssign
运算符,因为其内部状态可以在任何地方编辑。例如:
// v--- define `list` with the immutable structure explicitly
var list: List<Int> = arrayListOf(1); //TODO: try change `var` to `val`
val addend = arrayListOf(2);
val snapshot = list;
list += addend;
// ^--- list = list.plus(addend);
// list = [1, 2], snapshot=[1], addend = [2]
// v--- `list` uses the mutable structure implicitly
val list = arrayListOf(1); //TODO: try change `val` to `var`
val addend = arrayListOf(2);
val snapshot = list;
list += addend;
// ^--- list.plusAssign(addend);
// list = [1, 2], snapshot=[1, 2], addend = [2]
var list = listOf<Int>();
list += 1; //list = [1];
// ^--- list = list.plus(Integer);
list += [2,3]; //list = [1, 2, 3]
// ^--- list = list.plus(Iterable);
另一方面,您可以使用不同的签名重载运算符,每个签名用于不同的上下文,kotlin也可以这样做,例如:。例如:
// v--- define `list` with the immutable structure explicitly
var list: List<Int> = arrayListOf(1); //TODO: try change `var` to `val`
val addend = arrayListOf(2);
val snapshot = list;
list += addend;
// ^--- list = list.plus(addend);
// list = [1, 2], snapshot=[1], addend = [2]
// v--- `list` uses the mutable structure implicitly
val list = arrayListOf(1); //TODO: try change `val` to `var`
val addend = arrayListOf(2);
val snapshot = list;
list += addend;
// ^--- list.plusAssign(addend);
// list = [1, 2], snapshot=[1, 2], addend = [2]
var list = listOf<Int>();
list += 1; //list = [1];
// ^--- list = list.plus(Integer);
list += [2,3]; //list = [1, 2, 3]
// ^--- list = list.plus(Iterable);
var list=listOf();
列表+=1//列表=[1];
//^---list=list.plus(整数);
列表+=[2,3]//列表=[1,2,3]
//^---list=list.plus(可编辑);
您的操作员覆盖实施存在两个问题:
1。plus之后的类型不一致
operator fun ObservableDoubleValue.plus(number: Number): DoubleProperty
= SimpleDoubleProperty(get() + number.toDouble())
任何可观察到的ubleValue
实例加上一个数字
,得到一个DoubleProperty
实例(或者说一个SimpleDoubleProperty
实例)。假设我有一个类型ComplexDoubleProperty
implementsobservedblevalue
,您将看到:
var a = getComplexDoubleProperty()
a = a + 0.1 //compile error, WTF?
//or even
var b = SimpleDoubleProperty(0.1)
b = b + 0.1 //compile error, because b+0.1 is DoubleProperty
你可以看到这种行为毫无意义
2。a=a+b和a+=b应该相同
如果您的实现已编译,您将
var a: DoubleProperty = SimpleDoubleProperty(0.1) //add DoubleProperty to make it compile
var b = a
a += 0.1
println(b == a)
打印true
,因为+=
将值设置为原始实例。如果将a+=0.1
替换为a=a+0.1
,将得到false
,因为返回了一个新实例。一般来说,a=a+b
和a+=b
在这个实现中并不相同
为了解决上述两个问题,我的建议是
operator fun SimpleDoubleProperty.plus(number: Number): SimpleDoubleProperty
= SimpleDoubleProperty(get() + number.toDouble())
因此,您不需要覆盖
plusAssign
。这个解决方案不像您的解决方案那样通用,但是如果您只有SimpleDoubleProperty
计算,那么它是正确的,我相信您是这样做的,因为在您的实现中,plus
总是返回一个SimpleDoubleProperty
实例。否,DoubleProperty是Java/JavaFX标准库中的一个类。这并不能回答这个问题。若要评论或要求作者澄清,请在其帖子下方留下评论。-@利亚姆好些了吗POn哪一行有错误?@voddan我在代码中添加了一条评论我接受1。但我不满足于返回我的属性的新实例,因为这几乎完全不符合重写plus()
和plusAssign()
的理由。例如,如果其他属性绑定到特定实例,并且您对其进行了plusAssign
,则changeEvent
将永远不会被触发,并且所有观察者都不会更新。