下面的代码将元素添加到res
列表中。我的问题是scala如何在内部翻译.::
个符号?
代码段:
var res = List[(Int, Int)]()
res .::= (1, 2)
res .::= (3, 4)
res
输出:
res56:List [(Int,Int)] = List((1,2),(3,4))
答案 0 :(得分:5)
该片段中有一些事情正在发生。在深入研究之前,让我们谈谈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
设置为包含字母&#34; a&#34;?
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")
也适用。
现在,让我们分解原始片段:
第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
mind = blown
我还建议您查看What are all the instances of syntactic sugar in Scala?
答案 1 :(得分:3)
.
(点)用于类实例上的方法调用。
::
是在List
::
是在List
类中声明的方法,它创建scala.collection.immutable.::
类的实例。
请注意::
是List类中的方法,而::
也是包scala.collection.immutable
以下是::
类
List
函数的实现
@SerialVersionUID(-6084104484083858598L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
sealed abstract class List[+A] extends AbstractSeq[A]
with LinearSeq[A]
with Product
with GenericTraversableTemplate[A, List]
with LinearSeqOptimized[A, List[A]]
with Serializable {
override def companion: GenericCompanion[List] = List
import scala.collection.{Iterable, Traversable, Seq, IndexedSeq}
def isEmpty: Boolean
def head: A
def tail: List[A]
// New methods in List
/** Adds an element at the beginning of this list.
* @param x the element to prepend.
* @return a list which contains `x` as first element and
* which continues with this list.
*
* @usecase def ::(x: A): List[A]
* @inheritdoc
*
* Example:
* {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
.....
}
以下是scala.collection.immutable.::
的定义方式。
@SerialVersionUID(509929039250432923L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
override def tail : List[B] = tl
override def isEmpty: Boolean = false
}
答案 2 :(得分:1)
的输出
var res = List[(Int, Int)]()
res .::= (1, 2)
res .::= (3, 4)
res
应该是
列表((3,4),(1,2))
因为the colon colon method ::会在列表的前面添加一个元素。
在这种情况下,点 .
完全是可选的 - 这只是为了明确说明您在列表对象::
上调用方法res
。这意味着您的代码与此代码相同:
var res = List[(Int, Int)]()
res ::= (1, 2)
res ::= (3, 4)
res
内部冒号结肠 ::
的实现方式如下:
/** Adds an element at the beginning of this list.
* @param x the element to prepend.
* @return a list which contains `x` as first element and
* which continues with this list.
*
* @usecase def ::(x: A): List[A]
* @inheritdoc
*
* Example:
* {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
*/
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
创建一个新列表(由于不变性),将参数作为第一个元素,将当前列表内容作为其余元素