是一种方法还是一类?

アレッ*_*ックス 11 scala

Marting Odersky在他的书中写道:

Class ::,发音为"cons"代表"construct",表示非空列表.

列表构造方法::和:::是特殊的.因为它们以冒号结束,所以它们与右操作数绑定.也就是说,诸如x :: xs之类的操作被视为方法调用xs.::(x),而不是x.::(xs).实际上,x.::( xs)没有意义,因为x是列表元素类型,它可以是任意的,所以我们不能假设这个类型有一个:: 方法.因此,:: method应该获取一个元素值并生成一个新列表

所以是::一个方法或类?

Ric*_*ver 16

它既是一个类,也是一个方法.Cons是一个类型参数化类.List [A]有两个子类:Cons和Nil.由于Cons是一个类,它可以通过其构造函数创建,如下所示:

val s = new ::[Int](4, Nil)
Run Code Online (Sandbox Code Playgroud)

Cons是一个case类,我们在进行模式匹配时使用构造函数.Cons也是列表类中的一个方法,它在两个子类中实现.因此,我们可以在上面创建的cons类中使用cons方法.

val s1 = s.::(5)
Run Code Online (Sandbox Code Playgroud)

可能会出现部分混淆,因为我们通常使用List对象的apply方法创建列表:

val s2 = List(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

通常,对象的apply方法返回与对象同名的Class的新实例.然而,这只是惯例.在这种特殊情况下,List Object返回Cons子类的新实例.List类本身是一个密封的抽象类,因此无法实例化.所以上面的apply方法做了以下几点:

val s2 = 1 :: 2 :: 3 :: Nil
Run Code Online (Sandbox Code Playgroud)

任何以':'结尾的方法都是右侧操作数上的方法,因此可以将其重写为

val s2 = 1 :: (2 :: (3 :: Nil)) //or as
val s2 = Nil.::(3).::(2).::(1)
Run Code Online (Sandbox Code Playgroud)

因此,Nil对象上的Cons(::)方法将3作为参数,并生成Cons类的匿名实例化,其中3为头部,对Nil对象的引用为尾部.让我们称这个匿名对象为c1.然后在c1上调用Cons方法,以2为参数返回一个新的匿名Cons实例,让我们称之为c2,其头部为2,c1为尾部.然后最后c2对象上的cons方法将1作为参数,并返回命名对象s2,其中1为头部,c2为尾部.

第二个困惑点是REPL和Scala工作表使用类'toString方法来显示结果.所以工作表给了我们:

val s3 = List(5, 6, 7)     // s3  : List[Int] = List(5, 6, 7)
val s4 = List()            // s4  : List[Nothing] = List()
val s5: List[Int] = List() // s5  : List[Int] = List()
s3.getClass.getName        // res3: String = scala.collection.immutable.$colon$colon
s4.getClass.getName        // res4: String = scala.collection.immutable.Nil$
s5.getClass.getName        // res5: String = scala.collection.immutable.Nil$
Run Code Online (Sandbox Code Playgroud)

如上所述,List是密封的,因此无法创建新的子子类,因为Nil是一个对象而Cons是最终的.由于Nil是一个对象,因此无法进行参数化.Nil继承自List [Nothing].乍一看听起来不那么有用,但记住这些数据结构是不可变的,所以我们永远不能直接添加它们,Nothing是其他所有类的子类.所以我们可以毫无问题地将Nil类(间接)添加到任何List中.Cons类有两个成员头和另一个List.当你计时时它是一个相当简洁的解决方案.

我不确定这是否有任何实际用途,但你可以使用Cons作为一种类型:

var list: ::[Int] = List (1,2,3).asInstanceOf[::[Int]]
println("Initialised List")
val list1 = Nil
list = list1.asInstanceOf[::[Int]] //this will throw a java class cast exception at run time
println("Reset List")
Run Code Online (Sandbox Code Playgroud)


Tra*_*own 5

简短回答:两者都有.

有一个名为的子类::,但你不会经常明确地引用它.

当你编写eg时1 :: 2 :: Nil,::一个方法 on List,它::在幕后创建一个类的实例.

::是最好的思想不为方法或类,虽然,但作为一个构造代数数据类型(ADT)感.维基百科称ADT构造函数为"准功能权利",这使得它们听起来比它们更复杂,但不一定是思考它们的坏方法.

List有两个构造函数::(在某些语言中称为cons)和Nil.我上面链接的维基百科文章很好地介绍了列表作为代数数据类型的概念.

值得注意的是,在某些语言(如Haskell)中,ADT构造函数没有与它们关联的自己的类型 - 它们只是创建ADT实例的函数.这在Scala中通常也是如此,其中很少引用ADT构造函数的类型::.但是有可能 - 我们可以这样写:

def foo(xs: ::[Int]) = ???
Run Code Online (Sandbox Code Playgroud)

或者这个(其中Some一个是OptionADT 的构造函数).

def bar(s: Some[Int]) = ???
Run Code Online (Sandbox Code Playgroud)

但这通常不是很有用,并且可以被认为是Scala实现代数数据类型的方式的工件.