【问题标题】:What does dot colon colon (.::) meaning in scala点冒号冒号(.::)在scala中的含义是什么
【发布时间】:2016-11-11 19:23:48
【问题描述】:

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

代码 sn-p:

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

输出:

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

【问题讨论】:

  • 输出应该是List((3,4), (1,2))

标签: scala


【解决方案1】:

在那个 sn-p 中发生了一些事情。在深入探讨之前,让我们先谈谈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 设置为包含字母“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?

【讨论】:

    【解决方案2】:

    只是方法调用

    .(点)用于类实例的方法调用。

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

    【讨论】:

      【解决方案3】:

      的输出
      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)
      

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

      【讨论】:

        猜你喜欢
        • 2019-09-14
        • 2012-09-25
        • 2012-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-01
        • 2016-05-16
        • 2011-08-28
        相关资源
        最近更新 更多