点冒号(.::)在Scala中是什么意思?

csga3l58  于 2022-11-09  发布在  Scala
关注(0)|答案(3)|浏览(234)

下面的代码将元素添加到res列表。我的问题是,Scala如何在内部转换.::符号?

代码片段:

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

输出:

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

j2cgzkjk

j2cgzkjk1#

这段代码中有几件事正在发生。在深入讨论之前,我们先来谈谈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")也可以使用。
现在,我们来分析一下原始的代码片段:

第一步

创建一个名为res的变量,并为其分配一个空的、不变的列表。此空列表旨在包含整数对(Int, Int)

var res = List[(Int, Int)]()

这里有一种替代方法来做同样的事情:

var res = List.empty[(Int, Int)]

(在我看来,它更容易阅读)

第二步

将新元素(1, 2)附加到列表res,并将结果列表重新分配回res

res .::= (1, 2)

或者,不带空格:

res.::=(1, 2)

看起来眼熟吗?我们也可以写成:

res = res.::(1, 2)

第三步

按照步骤2中的逻辑准备(3, 4)

第四步

打印出res的当前值,应为:List((3,4), (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?

bz4sfanl

bz4sfanl2#

只调用方法

用于对类的示例进行方法调用的.(点)。
::是在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
}
hlswsv35

hlswsv353#

的产出

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

应该是
列表((3,4),(1,2))
因为冒号方法::将一个元素添加到列表的前面。

.在这种情况下是完全可选的-这只是为了明确说明,您正在对列表对象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)

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

相关问题