话说模式匹配(6) case类的细节

我们在第二篇文章里曾提到过:

本质上case class是个语法糖,对你的类构造参数增加了getter访问,还有toString, hashCode, equals 等方法; 最重要的是帮你实现了一个伴生对象,这个伴生对象里定义了apply方法和unapply方法。

现在我们来详细的分析一下case class,对一个简单的样本类

case class B()

反编译后看到编译器自动给它混入了Product特质,以及Serializable特质:

public class B implements scala.Product,scala.Serializable {
 public B copy();
 public java.lang.String productPrefix();
 public int productArity();
 public java.lang.Object productElement(int);
 public scala.collection.Iterator<java.lang.Object> productIterator();
 public boolean canEqual(java.lang.Object);
 public int hashCode();
 public java.lang.String toString();
 public boolean equals(java.lang.Object);
 public B();
}

再看看它的半生对象:

//伴生对象也混入了AbstractFunction0 和 Serializable 特质
public final class B$ extends scala.runtime.AbstractFunction0<B> implements scala.Serializable {
 public static final B$ MODULE$;
 public static {};
 public final java.lang.String toString();
 public B apply();
 public boolean unapply(B);
 public java.lang.Object apply();
}

通过反编译的结果我们了解到了几点:

  1. 编译器对case类混入了Product特质
  2. 编译器对case类增加了copy方法;
  3. 编译器对case类实现了equals/hashCode/toString等方法
  4. 伴生对象中最重要的方法是 unapply 这个方法是在进行构造器模式匹配时的关键。
  5. 伴生对象中apply方法则为创建对象提供方便,相当于工厂方法。
  6. 伴生对象继承了AbstractFunction

从case类的设计目的来看,最重要的是提供构造器模式匹配(且构造时的参数,与解构的结果一致),另外case类可看作是数据对象,不可变的数据对象。

因为case类封装的数据有不变的特点,以及可以进行模式匹配,所以它在actor中经常使用,很适合封装消息在actor之间传递。

上面列出的几点中,对于第6点“伴生对象继承自 Function”可能感到奇怪,Martin在这里回答了为什么case类的伴生对象会继承FunctionN

The reason why case class companion objects implement FunctionN is that before, case classes generated a class and a factory method, not a companion object. When we added extractors to Scala it made more sense to turn the factory method into a full companion object with apply and unapply methods. But then, since the factory method did conform to FunctionN, the companion object needed to conform, too.

另外,当参数大于2个时,FunctionN 都提供了tupled方法生成一个函数,该函数可以接受一个tuple作为参数构造出结果,比如:

scala> case class A(x: Int, y:Int)

scala> A.tupled
res11: ((Int, Int)) => A = <function1>

scala> val t = (100,100)
t: (Int, Int) = (100,100)

scala> A.tupled(t)
res9: A = A(100,100)
文章转自 并发编程网-ifeve.com
上一篇:安卓巴士Android开发者门户


下一篇:艾伟_转载:Visual Studio调试之断点进阶篇