长时间潜伏,第一次海报.
在Scala中,我正在寻找优势,以便根据类型改变运算符.例如,为什么这样:
Vector(1, 2, 3) :+ 4
Run Code Online (Sandbox Code Playgroud)
决心成为优势:
Vector(1, 2, 3) + 4
Run Code Online (Sandbox Code Playgroud)
要么:
4 +: Vector(1,2,3)
Run Code Online (Sandbox Code Playgroud)
过度:
Vector(4) + Vector(1,2,3)
Run Code Online (Sandbox Code Playgroud)
要么:
Vector(1,2,3) ++ Vector(4,5,6)
Run Code Online (Sandbox Code Playgroud)
过度:
Vector(1,2,3) + Vector(4,5,6)
Run Code Online (Sandbox Code Playgroud)
所以,这里我们有:+,+:和++当+单独就足够了.我是斯卡拉的新人,我会屈服.但是,对于一种试图用它的语法来清理的语言来说,这似乎是不必要的和混淆的.
我已经做了很多google和堆栈溢出搜索,并且只发现了有关特定运算符和运算符重载的问题.但是,没有背景为什么有必要将+分成例如多个变体.
FWIW,我可以使用隐式类重载运算符,如下所示,但我想这只会导致经验丰富的Scala程序员使用/读取我的代码时产生混淆(和tisk风险).
object AddVectorDemo {
implicit class AddVector(vector : Vector[Any]) {
def +(that : Vector[Any]) = vector ++ that
def +(that : Any) = vector :+ that
}
def main(args : Array[String]) : Unit = {
val u = Vector(1,2,3)
val v = Vector(4,5,6)
println(u + v)
println(u + v + 7)
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
矢量(1,2,3,4,5,6)
矢量(1,2,3,4,5,6,7)
答案需要通过差异进行令人惊讶的长途跋涉.我会尽量让它尽可能短.
首先,请注意您可以向现有Vector添加任何内容:
scala> Vector(1)
res0: scala.collection.immutable.Vector[Int] = Vector(1)
scala> res0 :+ "fish"
res1: scala.collection.immutable.Vector[Any] = Vector(1, fish)
Run Code Online (Sandbox Code Playgroud)
你为什么这样做?好吧,如果B extends A我们希望能够使用所需的Vector[B]地方Vector[A],我们需要允许Vector[B]添加可以添加的相同类型的东西Vector[A].但是一切都在扩展Any,所以我们需要添加任何Vector[Any]可以添加的东西,这就是一切.
制作Vector和大多数其他非Set集合协变是一个设计决定,但它是大多数人所期望的.
现在,让我们尝试向矢量添加矢量.
scala> res0 :+ Vector("fish")
res2: scala.collection.immutable.Vector[Any] = Vector(1, Vector(fish))
scala> res0 ++ Vector("fish")
res3: scala.collection.immutable.Vector[Any] = Vector(1, fish)
Run Code Online (Sandbox Code Playgroud)
如果我们只有一个操作,+我们将无法指定我们所指的这些东西中的哪一个.而且我们真的可能会这样做.他们都是非常明智的尝试.我们可以尝试根据类型进行猜测,但实际上最好只要求程序员明确说出它们的含义.由于有两个不同的含义,需要有两种方式可以提出.
这是否在实践中出现?随着收藏集,是的,所有的时间.例如,使用您的+:
scala> Vector(Vector(1), Vector(2))
res4: Vector[Vector[Int]] = Vector(Vector(1), Vector(2))
scala> res4 + Vector(3)
res5: Vector[Any] = Vector(Vector(1), Vector(2), 3)
Run Code Online (Sandbox Code Playgroud)
那可能不是我想要的.
这是一个公平的问题,我认为它与遗留代码和Java兼容性有很大关系.Scala复制了Java +用于字符串连接,这使事情变得复杂.
这+允许我们这样做:
(new Object) + "foobar" //"java.lang.Object@5bb90b89foobar"
Run Code Online (Sandbox Code Playgroud)
所以,我们应该想到,如果我们有+对List我们做了List(1) + "foobar"?人们可能期望List(1, "foobar")(类型List[Any]),就像我们使用的那样:+,但是Java启发的String-concatenation重载会使这变得复杂,因为编译器将无法解决重载.
奥德斯基甚至曾评论过:
对于在其元素类型中具有协变性的集合,应该永远不会有+方法.集合和映射是非变量的,这就是为什么它们可以有+方法.这一切都相当精致和凌乱.如果我们不尝试复制Java的+用于字符串连接,我们会更好.但是当Scala得到设计时,我们的想法就是保留Java的所有表达式语法,包括String +.现在改变它已经太晚了.
关于这个类似问题的答案,有一些讨论(尽管在不同的背景下).
| 归档时间: |
|
| 查看次数: |
90 次 |
| 最近记录: |