解释scala中unapply方法的工作原理

时间:2017-10-23 19:59:27

标签: scala

我是否正确理解了流量?考虑以下代码

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"
}

我是否更正eTokenizer.unapply(x:Employee)传递给Some()并将(c,d)的结果分配给Tokenizer(c,d)?从代码的外观来看,似乎我们正在调用apply,但没有unapplyTokenizer(c,d)方法定义为http://12.0.0.1:8000/whatever的签名simialar

2 个答案:

答案 0 :(得分:1)

是的,您已正确理解。 unapply可能有点弯曲,因为当您在case中看到它时,您会编写返回类型而不是参数类型Tokenizer.unapply的签名是Employee => Some[(String, String)]。与case Tokenizer(c, d)对应的部分是返回类型。

然而,我有几个(非常小的)尼特选择。您应该为所有公共方法提供类型,因为您最终可能会推断出太具体的类型(通过推断Some而不是Option来显示),然后更改您的代码(在这种情况下,也许这样做Tokenizer.unapply可能会失败并None}更改其界面。但是,如果您希望赢得 更改Tokenizer以便能够失败,则无需通过返回{{1}来承受拳击惩罚}。你可以改为

Option

最后一点:调用一个没有双重parens的元组的函数是不好的。别写// 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 ;写Some(a, b)。这有点难看,但第一个可能含糊不清,而且情况更糟。

答案 1 :(得分:0)

An object with an unapply method is an extractor object. It does the inverse of the apply method by extracting the individual values that were passed to apply. So in the above example result will contain the tuple ("Kurt", "Vonnegut").

Note that you could also use an assignment instead of pattern matching here:

$ val Tokenizer(emp) = e
emp: (String, String) = ("Kurt", "Vonnegut")