来源:Scala MEAP v10中的功能编程
在下面粘贴的代码中
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
def sum(ints: List[Int]): Int = ints match {
case Nil => 0
case Cons(x,xs) => x + sum(xs)
}
def product(ds: List[Double]): Double = ds match {
case Nil => 1.0
case Cons(0.0, _) => 0.0
case Cons(x,xs) => x * product(xs)
}
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
val example = Cons(1, Cons(2, Cons(3, Nil)))
}
Cons对象可能是由apply()构造的,但是类型签名是不同的,scala如何最终组装Cons实例。
虽然没有不适用,但下面的代码工作得很好,将List拆成Cons(head,tail)
object a{
val x = List(1,2,3,4,5) match {
case Cons(x, Cons(2, Cons(4, _))) => x
case Nil => 42
case Cons(x, Cons(y, Cons(3, Cons(4, _)))) => x + y
case Cons(h, t) => h + List.sum(t)
case _ => 101
}
}
答案 0 :(得分:5)
Cons
实例始终由Cons
'构造函数。你可以直接打电话:
val myList = new Cons(1, new Cons(2, Nil)) // list containing the elements 1 and 2
随播对象上的apply
方法是一种工厂方法,允许您使用更好的语法构造列表:
val myList = List(1, 2) // expanded to List.apply(1, 2) by the compiler ; same result as above
他们没有理由需要使用相同类型的签名,因为他们不需要以相同的方式调用。
至于为什么你可以在不定义unapply
方法的情况下使用模式匹配:因为你将Nil
和Cons
定义为案例类/对象。案例类免费获取许多功能(由编译器生成),包括unapply
方法(例如equals
,hashcode
和toString
。< / p>
编辑:基于评论的一些精确性:
Scala中的构造函数: 在Scala中,每个类都有一个默认构造函数,其参数可自动作为类中的字段使用 - 因此默认构造函数不需要拥有自己的方法体。例如,以下Scala类:
class Foo1(bar: Int)
class Foo2(val bar: Int)
大致相当于以下Java类:
public class Foo1 {
public Foo1(int bar) {
this.bar = bar;
}
private int bar;
}
public class Foo2 {
public Foo2(int bar) {
this.bar = bar;
}
private int bar;
public int getBar() {
return bar;
}
}
<强>多形性:强>
Nil
和Cons
都延伸List
。这意味着 Cons
是一种List
。因此,如果您使用Cons
创建val myList = new Cons(1, Nil)
的实例,则myList
是Cons
类型的对象...但它也是:
List
AnyRef
的AnyRef
,因此List
扩展AnyRef
(因为它没有明确的extends
子句。)Any
,它是所有Scala类型的根。以下代码使用您的List
/ Cons
/ Nil
实施:
val myList = List(1, 2, 3)
// Cons(1,Cons(2,Cons(3,Nil))) => result of the toString method generated by the compiler because it's a case class
myList.getClass.getName
// Cons => this is the concrete type of myList
myList.isInstanceOf[Cons[_]]
// true => myList is a Cons
myList.isInstanceOf[Nil.type]
// false
myList.isInstanceOf[List[_]]
// true => but it's also a kind of List
val foo: List[Int] = myList
// => this is allowed
myList.isInstanceOf[AnyRef]
// true
myList.isInstanceOf[Any]
// true
val anotherList = List()
// Nil
anotherList.getClass.getName
// Nil$ => the name is mangled with a $ sign to differentiate the 'object Nil' in case you also declare a 'class Nil'
anotherList.isInstanceOf[List[_]]
// true