cons 是方法还是类? [英] Is cons a method or a class?

查看:33
本文介绍了cons 是方法还是类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Marting Odersky 在他的书中写道:

Marting Odersky in his book writes:

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

Class ::, pronounced "cons" for "construct," represents non-empty lists.

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

The list construction methods :: and ::: are special. Because they end in a colon, they are bound to their right operand. That is, an operation such as x :: xs is treated as the method call xs.::(x), not x.::(xs). In fact, x.::(xs) would not make sense, as x is of the list element type, which can be arbitrary, so we cannot assume that this type would have a :: method. For this reason, the :: method should take an element value and yield a new list

那么 :: 是方法还是类?

So is :: a method or a class?

推荐答案

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

It is both a class and a method. Cons is a type parametised class. List[A] has two sub classes: Cons and Nil. As Cons is a class it can be created by its constructor as follows:

val s = new ::[Int](4, Nil)

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

Cons is a case class and we use the constructor when we do a pattern match. Cons is also a method on the list class that is implemented in its two sub classes. Hence we can use the cons method on the cons class that we have created above.

val s1 = s.::(5)

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

Part of the confusion may arise, because we normally create Lists using the apply method of the List object:

val s2 = List(1, 2, 3)

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

Normally the apply method of an object returns a new instance of the Class with the same name as an object. This is however just convention. In this particular case the List Object returns a new instance of the Cons subclass. The List class itself is a sealed abstract class so can not be instantiated. So the above apply method does the following:

val s2 = 1 :: 2 :: 3 :: Nil

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

Any method that ends in a ':' is a method on the operand to its right so it can be rewritten as

val s2 = 1 :: (2 :: (3 :: Nil)) //or as
val s2 = Nil.::(3).::(2).::(1)

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

So the Cons(::) method on the Nil object takes the 3 as a parameter and produces an anonymous instantiation of the Cons class with 3 as its head and a reference to the Nil object as its tail. Lets call this anonymous object c1. The Cons method is then called on c1 taking 2 as its parameter returning a new anonymous Cons instantiation lets call it c2, which has 2 for its head and a reference to c1 as its tail. Then finally the cons method on the c2 object takes the 1 as a parameter and returns the named object s2 with 1 as its head and a reference to c2 as its tail.

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

A second point of confusion is that the REPL and Scala worksheets use a class' toString methods to display results. So the worksheet gives us:

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$

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

As said above List is sealed so new sub sub classes can not be created as Nil is an object and Cons is final. As Nil is an object it can't be parametrised. Nil inherits from List[Nothing]. At first glance that doesn't sound that useful but remember these data structures are immutable, so we can never add to them directly and Nothing is a sub class of every other class. So we can add the Nil class (indirectly) to any List without problem. The Cons class has two members a head and another List. Its a rather neat solution when you clock it.

我不确定这是否有任何实际用途,但您可以将 Cons 用作类型:

I'm not sure if this has any practical use but you can use Cons as a type:

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")

这篇关于cons 是方法还是类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆