在那个 sn-p 中发生了一些事情。在深入探讨之前,让我们先谈谈var 和val 之间的区别。也就是说,使用val 关键字声明的变量是不可变的,即它的值不能改变:
scala> val x = 1
x: Int = 1
scala> x = 2
<console>:13: error: reassignment to val
x = 2
^
另一方面,var 关键字用于声明可变变量,即其值可以改变:
scala> var y = "bar"
y: String = bar
scala> y = "foo"
y: String = foo
如果我们想通过附加到当前值来计算 y 的新值怎么办?
scala> y = y + "bar"
y: String = foobar
当然可以,但事实证明有一个速记:
scala> y += "bar"
scala> y
res10: String = foobar
顺便说一句,在 Scala 中,+ 只是一个方法的名称,所以y + "bar" 与y.+("bar") 相同。丑陋,但有效。同样,y.+=("bar") 也是y += "bar" 的有效替换。
太好了,让我们记住这一点以备后用。接下来,正如其他人已经指出的那样,:: 只是一个将元素添加到列表的方法(在 Java 中它可以调用为someList.$colon$colon(someElement))。需要注意的重要一点是:: 方法返回一个新列表:
scala> var letters = List("b", "c")
letters: List[String] = List(b, c)
scala> letters.::("a")
res1: List[String] = List(a, b, c)
scala> letters
res2: List[String] = List(b, c)
如果我们想将letters 设置为包含字母“a”的列表怎么办?
scala> letters = letters.::("a")
letters: List[String] = List(a, b, c)
请注意,这看起来与前面的字符串示例非常相似。速记在这里也有用吗?
scala> letters ::= "a"
scala> letters
res6: List[String] = List(a, b, c)
是的,确实如此。 letters.::=("a") 也可以。
现在,让我们分解一下原来的sn-p:
第 1 步
创建一个名为res 的变量并为其分配一个空的、不可变的列表。这个空列表旨在包含整数对(Int, Int)。
var res = List[(Int, Int)]()
这是做同样事情的另一种方法:
var res = List.empty[(Int, Int)]
(在我看来,这更容易阅读)
第 2 步
将新元素 (1, 2) 添加到列表 res 并将结果列表重新分配回 res。
res .::= (1, 2)
或者,没有空格:
res.::=(1, 2)
看起来很眼熟?我们也可以写成:
res = res.::(1, 2)
第 3 步
按照步骤 2 中的逻辑添加 (3, 4)
第 4 步
打印出res的当前值,应该是:List((3,4), (1,2))
旁注
令人困惑的是,编译器足够宽松,允许我们在调用:: 时只指定一组括号,尽管我们确实应该有两组:一组用于方法调用,另一组用于指示一对整数.所以,碰巧还有另一个有效的
写同一件事的方式res.::=((1, 2))。
更笼统地说:
scala> def first(p:(Int, Int)):Int = p._1
first: (p: (Int, Int))Int
scala> first(6,7)
res0: Int = 6
scala> first((6,7))
res1: Int = 6
scala> first(6 -> 7) //lolz! another one using implicit conversion
res2: Int = 6
隐式转换一直存在,因为它是在 Predef.ArrowAssoc 中定义的
头脑 = 吹爆
我也推荐看看What are all the instances of syntactic sugar in Scala?