我对流程的理解正确吗?考虑下面的代码
class Employee(val firstName: String, val middleName: Option[String], val lastName: String)
object Tokenizer {
def unapply(x: Employee) = Some(x.firstName, x.lastName)
}
val e = new Employee("Kurt", None, "Vonnegut")
val result = e match {
case Tokenizer(c, d) ⇒ "c: %s, d: %s".format(c, d)
case _ ⇒ "Not found"
}e将被传递给Tokenizer.unapply(x:Employee),Some()的结果被赋值给(c,d),我说的对吗?从代码的外观看,我们似乎在调用Tokenizer(c,d),但没有使用类似于Tokenizer(c,d)的签名定义apply或unapply方法
发布于 2017-10-24 04:54:14
是的,你理解得没错。unapply可能有点让人费解,因为当您在case中看到它时,您编写的是它的返回类型,而不是参数类型。Tokenizer.unapply的签名是Employee => Some[(String, String)]。与case Tokenizer(c, d)对应的部分是返回类型。
然而,我有几个(非常小的)nit要挑选。您应该为所有的公共方法指定类型,因为您最终可能会推断出过于具体的类型(它在这里通过推断Some而不是Option来显示),然后更改您的代码(在本例中,可能会使它变得可能会因为None而失败)更改它的接口。但是,如果您希望不会更改Tokenizer使其失败,那么就不需要通过返回Option来招致装箱惩罚。相反,您可以这样做
// Don't worry if you don't understand this yet. You can ignore this trick and come back to it much later
// Also: I think this only works on Scala 2.12
final case class Box[+T](t: T) extends AnyVal {
def isEmpty = false
def get = t
}
object Tokenizer {
def unapply(e: Employee): Box[(String, String)] = Box((e.firstName, e.lastName))
}
// Incurs no boxing penalty, but now you can't change it to allow failure without changing the interface最后的nit:调用一个需要没有双括号的元组的函数是一种糟糕的风格。不要写Some(a, b);要写Some((a, b))。它有点难看,但第一个可能是模棱两可的,那就更糟了。
发布于 2017-10-24 04:47:56
具有unapply方法的对象是提取器对象。它通过提取传递给apply的各个值来执行与apply方法相反的操作。因此,在上面的示例中,result将包含元组("Kurt", "Vonnegut")。
注意,您也可以在这里使用赋值而不是模式匹配:
$ val Tokenizer(emp) = e
emp: (String, String) = ("Kurt", "Vonnegut") https://stackoverflow.com/questions/46897529
复制相似问题