2011-09-01 122 views
13
令行禁止构造他们似乎

不混那么好:case类,模式匹配和斯卡拉

abstract class A 
case class B (var a: Int)(var b: String) extends A 
case class C extends A 

下将无法正常工作:

B(1)("1") match { 
    case B(a)(b) => print("B") 
    case C() => print("C") 
} 

的问题是,模式匹配和curried的论点似乎并不奏效。有没有解决这个问题的方法?

回答

7

这是怎么回事?

def m(a: A) = a match { 
    case b: B => print("B") 
    case c: C => print("C") 
} 

我只问,因为你没有要求比这更多的功能。

编辑

这可以帮助:

object Dog { 
    def apply(name: String)(size: Int) = new Dog(name)(size) 
    def unapply(dog: Dog) = Some(dog.name, dog.size) 
} 
class Dog(val name: String)(var size: Int) 

现在你可以创建或者狗这样的:

new Dog("Snoopy")(10) 

或像这样:

Dog("Snoopy")(10) 

但是,当你对狗的模式匹配时,构造函数模式是而不是咖喱。

Dog("Snoopy")(10) match { 
    case Dog(a, b) => // do sth with a or b 
} 
+0

你的第一个例子可以工作,但是我不能在case语句中访问B.a和B.b,而不做一些丑陋的类型转换。另外,在你的编辑中,我不确定我是否理解为什么构造函数模式没有被粘贴。是因为不适用? –

+0

说实话,我不知道它为什么起作用。我通过反复试验偶然发现了它。这绝对是在Scala规范中的某处提到的。如果它与您的案例相关,您可能想查看它。 – agilesteel

+1

是的,您在case语句中使用的模式是由unapply函数的结果给出的模式。它永远不会被咖喱。 scala规范中的相应部分是§8.1.8 – Nicolas

2

您可以使用普通的案例类,只需定义一个具有多个参数列表的工厂方法。

+0

可能我们可以补充一点,如果工厂方法在伴随对象中声明,就不能使用'apply'进行升级(因为它会和第其中一个表示感谢案例分类)。 – Nicolas

11

如果你看一下B类创建不应用功能的签名,你会看到,它是:unapply(x$0: Q): Option[Int]。因此,unapply函数可以处理案例类的第一个参数范围。

它由阶规范(第5.3.2节)证实:

的情况下类 的第一个参数部分形式参数被称为元素;他们被特别对待。首先, 这个参数的值可以作为构造函数模式的字段提取出来。

它声称只有第一个参数部分可通过提取器。

几种解决方法:

  • uncurry您的参数
  • ,如果你要测试的2个值使用带保护与模式匹配:case [email protected](3) if x.b == "bazinga" => ...
  • 使用一个普通的类,并定义自己的伴侣对象的自己申请/不申请