为什么运营商有差异?

16 浏览
0 Comments

为什么运营商有差异?

我长期以来一直在关注,这是我第一次发帖。

在Scala中,我正在寻找优势,看看为什么喜欢根据类型改变操作符。例如,为什么这样做:

Vector(1, 2, 3) :+ 4

被确定为优势,而不是:

Vector(1, 2, 3) + 4

或:

4 +: Vector(1,2,3)

而不是:

Vector(4) + Vector(1,2,3)

或者:

Vector(1,2,3) ++ Vector(4,5,6)

而不是:

Vector(1,2,3) + Vector(4,5,6)

所以,我们有:+、+:和++,当仅使用+就足以满足时。我是Scala的新手,我会接受。但是,这似乎是一个不必要的、混淆的语言,试图在语法上保持清晰。

我做了很多谷歌和堆栈溢出搜索,只找到了有关特定运算符和运算符重载的问题。但是,没有关于为什么必须将+等拆分为多个变体的背景。

附言,我可以使用隐式类重载运算符,如下面所示,但我想这只会引起经验丰富的Scala程序员使用/阅读我的代码时的困惑和不满。

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)
    }
}

输出:

Vector(1, 2, 3, 4, 5, 6)

Vector(1, 2, 3, 4, 5, 6, 7)

admin 更改状态以发布 2023年5月23日
0
0 Comments

这是一个很公平的问题,我认为和遗留代码和Java兼容性有很大关系。Scala复制了Java的字符串连接的+,这使得事情变得更加复杂。这个+可以让我们做到:

(new Object) + "foobar" //"java.lang.Object@5bb90b89foobar"

。那么如果我们用+来连接List,并且执行List(1) + "foobar",我们能得到什么呢?有人可能会期望得到List(1, "foobar")(类型为List[Any]),就像我们用:+时得到的一样,但Java风格的字符串重载会使这个问题变得复杂,因为编译器无法解析重载。Odersky曾经评论过:

在元素类型协变的集合中,绝不能有+方法。集合和映射都是非协变的,所以它们可以有+方法。这一切都相当微妙和混乱。如果我们不试图复制Java的字符串连接+,我们会更好。但是当Scala被设计时,想法是尽可能保留Java的所有表达式语法,包括字符串+。现在改变已经太迟了。

有一些讨论(虽然是在不同的上下文中)在这个类似的问题的回答中

0
0 Comments

答案需要一个令人惊讶的长方差旅程。我会尽可能地简短说明。

首先,请注意您可以向现有的Vector添加任何内容:

scala> Vector(1)
res0: scala.collection.immutable.Vector[Int] = Vector(1)
scala> res0 :+ "fish"
res1: scala.collection.immutable.Vector[Any] = Vector(1, fish)

为什么可以这样做?如果B extends A,并且我们想要能够使用Vector[A]要求Vector[B],我们需要允许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)

如果我们只有一个操作+,我们将无法指定我们要添加的哪个内容。而且我们可能真的想做其中任何一种。这两种尝试都是非常合理的。我们可以根据类型猜测,但实际上最好是要求程序员明确表示他们的意思。由于有两种不同的意思,因此需要有两种不同的询问方式。

这在实践中出现过吗?使用集合的集合,是的,一直如此。例如,使用+

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)

那可能不是我想要的。

0