如何解决为什么运算符关联性对于 Scala 3 扩展方法和常规方法的工作方式不同?
当我手动将 Scala 2 代码转换为 Scala 3 时,我的 DSL 的运算符优先级发生了变化,我花了很长时间进行调试和修复。 :
的处理似乎有所不同:
extension (i1: Int) def ~>:(i2: Int) = i1 < i2
extension (i1: Int) def ~>(i2: Int) = i1 < i2
class Wrap(val i: Int):
def ~>:(w: Wrap) = i ~>: w.i
def ~>(w: Wrap) = i ~> w.i
// `Wrap` preserves `~>`
println(1 ~> 2) // true
println(Wrap(1) ~> Wrap(2)) // true
// `Wrap` does not preserve `~>:`
println(1 ~>: 2) // true
println(Wrap(1) ~>: Wrap(2)) // false
我的心智模型是:
我的心智模型似乎是错误的。解释正在发生的事情的正确方法是什么?
链接会有所帮助,我检查了 Scala 3 文档,但没有找到有关自定义运算符如何关联的任何信息。
更新
我尝试在 infix
之前添加 def
关键字,但它不会更改此示例中打印的内容。
解决方法
你的心智模型只需要进行一些调整。
回想一下,中缀 x op y
去糖化为 x.op(y)
,除非操作以冒号结尾,否则它是 y.op:(x)
。无论 op()
方法是实例参数的原生方法还是附加的扩展,这都适用,在 Scala-2 中,由中间隐式类处理。
implicit class IntermediateClass(instance: Int) {
def op(arg: Int) = ???
}
另一方面,Scala-3 extension
只是一个接收两个柯里化参数的方法。所以中缀调用 leftOfOp op rightOfOp
将始终这样处理:
extension (leftOfOp: Int)
def op(rightOfOp: Int) = ???
无论 op
是否有尾随 :
都是一样的。但是,虽然定义站点的代码以这种方式保持一致,但调用站点的关联性却如您所料。
extension (left: String)
def @:(right: String):String = s"$left.@:($right)"
def @@(right: String):String = s"$left.@@($right)"
"TOP" @: "MID" @: "END" //"TOP.@:(MID.@:(END))"
"top" @@ "mid" @@ "end" //"top.@@(mid).@@(end)"
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。