具有自定义unapply的值类,是否会被实例化?

时间:2015-12-06 19:29:44

标签: scala

来自http://docs.scala-lang.org/overviews/core/value-classes.html

  

在以下情况下实际实例化值类:

     
      
  • 将值类视为另一种类型。
  •   
  • 将值类分配给数组。
  •   
  • 进行运行时类型测试,例如模式匹配。
  •   

我想知道第三项是否意味着任何模式匹配将导致实例化,或者是否特定于isInstanceOf项检查。

例如,如果我定义一个值类,如:

class Tag(val opening: StartElement) extends AnyVal {
  def name: QName = opening.getName
}
object Tag {
  def unapply(tag: Tag): Option[String] = {
    Some(tag.name.getLocalPart)
  }
}

然后像......一样使用它。

def matchStack(stack: List[Tag]) = stack match {
  case Tag("a") :: Tag("b") :: _ => "ab"
  case _ => "something else"
}

是否会实例化Tag?有没有办法检查(在运行时,还是在编译时)是否已实例化值类?

1 个答案:

答案 0 :(得分:4)

unapply方法本身不会封装AnyVal。请参阅下面的java字节码。请注意,unapply方法采用StartElement,而不是Tag。

但是在列表的上下文中使用AnyVal肯定会将其打包。 。当与 任何 集合(甚至是数组)一起使用时,AnyVals将被装箱。他们没有盒装的唯一情况是他们是另一个班级的直接成员。

scala> :paste
class StartElement { def getName: String = "foo" }
class Tag(val opening: StartElement) extends AnyVal { def name: String = opening.getName }
object Tag { def unapply(tag: Tag): Option[String] = Some(tag.name) }

scala> :javap -c Tag$
Compiled from "<console>"
public class Tag$ {

  public scala.Option<java.lang.String> unapply(StartElement);
    Code:
       0: new           #16                 // class scala/Some
       3: dup
       4: aload_0
       5: aload_1
       6: invokevirtual #20                 // Method name$extension:(LStartElement;)Ljava/lang/String;
       9: invokespecial #23                 // Method scala/Some."<init>":(Ljava/lang/Object;)V
      12: areturn
}

(在不使用StartElementQName之类的不受约束的类型的情况下发布自包含的示例会使这种分析变得更容易)