长时间潜伏,第一次海报。
在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)
所以,这里我们有:+,+:和++当+单独就足够了。我是斯卡拉的新人,我会屈服。但是,这个似乎是不必要的,并且对于试图用它的语法来清理的语言进行了混淆。
我做了很多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)
}
}
输出:
矢量(1,2,3,4,5,6)
矢量(1,2,3,4,5,6,7)
答案 0 :(得分:6)
答案需要通过差异进行令人惊讶的长途跋涉。我会尽量缩短它。
首先,请注意您可以向现有Vector添加任何内容:
B extends A
你为什么这样做?好吧,如果Vector[B]
并且我们希望能够使用Vector[A]
来调用Vector[B]
,我们需要允许Vector[A]
添加Any
相同类型的内容Vector[Any]
1}}可以添加。但是所有内容都延伸Vector
,因此我们需要添加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)
可以添加的任何内容,这就是一切。
使+
和大多数其他非Set集合协变是设计决策,但它是大多数人所期望的。
现在,让我们尝试向矢量添加矢量。
+
如果我们只有一个操作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)
,我们就无法指定我们所指的这些内容中的哪一个。我们真的可能意味着做任何一件事。他们尝试的都是非常明智的事情。我们可以尝试根据类型进行猜测,但在实践中,最好只要求程序员明确说出它们的含义。由于有两个不同的含义,需要有两种方式来提问。
这是否在实践中出现?随着收藏集,是的,所有的时间。例如,使用您的require 'rails_helper'
RSpec.describe GetBazsForBars, type: :service do
describe ".call" do
before { stub_const("Foo", FakeFoo) } # <-- added this
let(:token) { Rails.configuration.x.test_token }
let(:bazs) { GetBazsForBars.call(token) }
it { expect(bazs.any?).to eq(true) }
end
end
:
class FakeFoo < Foo
def bars
VCR.use_cassette("foo_bars") do
super()
end
end
end
这可能不是我想要的。
答案 1 :(得分:5)
这是一个公平的问题,我认为它与遗留代码和Java兼容性有很大关系。 Scala复制了Java的+
用于字符串连接,这使事情变得复杂。
这个+
允许我们这样做:
(new Object) + "foobar" //"java.lang.Object@5bb90b89foobar"
那么,如果+
List
List(1) + "foobar"
我们List(1, "foobar")
,我们应该期待什么?人们可能期望List[Any]
(类型为:+
),就像我们使用window.addEventListener("beforeunload", function(event) {
$.ajax({
url: api_disconnect,
data: { identifier: token },
method: "GET"
});
});
一样,但是Java启发的字符串连接重载会使这变得复杂,因为编译器将无法解决过载问题。
奥德斯基甚至曾经评论过:
对于在其元素类型中具有协变性的集合,应该永远不会有+方法。集合和映射是非变量的,这就是为什么它们可以有+方法。这一切都相当精致和凌乱。如果我们不尝试复制Java的+用于字符串连接,我们会更好。但是当Scala得到设计时,我们的想法就是保留Java的所有表达式语法,包括String +。现在改变它已经太晚了。
对this similar question的答案进行了一些讨论(尽管在不同的背景下)。