什么是点冒号冒号(。::)在scala中的含义

时间:2016-11-11 19:23:49

标签: scala

下面的代码将元素添加到res列表中。我的问题是scala如何在内部翻译.::个符号?

代码段:

var res = List[(Int, Int)]()
res .::= (1, 2)
res .::= (3, 4)
res

输出:

  

res56:List [(Int,Int)] = List((1,2),(3,4))

3 个答案:

答案 0 :(得分:5)

该片段中有一些事情正在发生。在深入研究之前,让我们谈谈varval之间的区别。也就是说,使用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

中的最终类

Scala标准库

以下是::

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)

创建一个新列表(由于不变性),将参数作为第一个元素,将当前列表内容作为其余元素