scala - cons 是方法还是类?

标签 scala

马丁·奥德斯基在他的书中写道:

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





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


::也是如此一个方法还是一个类?

最佳答案

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

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

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

部分混淆可能会出现,因为我们通常使用 List 对象的 apply 方法创建 Lists:
val s2 = List(1, 2, 3)

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

任何以“:”结尾的方法都是其右侧操作数上的方法,因此可以将其重写为
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 的引用作为尾部。

第二个混淆点是 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$

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

关于scala - cons 是方法还是类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19426548/

相关文章:

json - 使用 for 表达式从可能为空的 JSON 值中提取选项

scala - 将 Option 中的值转换为另一种类型

scala - 如何查看 Scala 用于自动生成案例类的 apply 函数的代码?

scala - 从 Spark 数据帧生成字段数组

java - 斯卡拉/Java : Ignore DateTimeException

scala - 使用 spark 读取压缩文件*带有自定义扩展名*

scala - 如何在 Scala 项目中组织导入?

scala - Akka - 是否有可能在 Actor 的主管中收到有关它失败的消息?

scala - 同时适用于 Int 和 Long 的通用隐式类

scala - redis ZADD <keys>在redis集群环境下是否一致?