在案例类中重载unapply方法:Scala

6

Consider the following piece of code:

case class User(id: Int, name: String)
object User{
  def unapply(str: String) = Some(User(0, str))
}

Scala抱怨“错误:无法解析重载的unapply; case class User(id:Int,str:String)” 不能重载unapply吗? 更新: 使用更大的元组大小进行unapply。
case class User(id: Int, str: String)
object User{
  def unapply(s: String) = Some((User(0, s), s, 1234))
}

编译器仍在抱怨“无法解析重载的unapply”。
2个回答

8

您的 unapply 方法无法在模式匹配中使用。

它适用于:

def unapply(arg: <type to match>) : Option[(<matched fields types>)]

如果只有一个字段,则不使用元组,如果没有字段,则使用布尔值而不是Option。

User的标准unapply如下(Scala语言规范第67页)

def unapply(u: User) = 
  if (u eq null) None 
  else Some((u.id, u.name))

如果您想将用户与零ID匹配,可以使用以下代码:

user match {case User(name) => ....}

那将会是:
def unapply(u: User): Option[String] = 
  if(u eq null || u.id != 0) None 
  else Some(u.name)

如果您希望一个字符串可以匹配为用户(这将非常奇怪)

def unapply(s: String): Option[User] = Some(User(0, s))

它可以与

"john" match case User(u) => ... // u is User(0, john)

我猜你想要前一种情况。在这种情况下,你的apply方法和标准方法都是具有相同参数列表(一个User参数)的两种方法,因此它们不兼容。这可能被看作是有点不幸的,因为当方法被调用为提取器时,区分元素实际上是结果元组的大小,而不是参数的类型。
然而,你的方法虽然不符合提取器的规则,但不会引起冲突。我在规范中找不到任何禁止它的内容。尽管如此,它是无用的,有用的方法应该是不允许的。

感谢您详细的解释!我的错...我在输入时忽略了一些用法。实际上,我正在寻找后一个(从字符串中提取用户)--上面的示例可能过于简化了真实情况。您提到区分元素实际上是元组大小,我试着为了完整性添加更多元组结果,但编译器没有反应。有任何想法为什么? - Ajay
2
你误解了我关于元组大小的意思。我是在后悔提取器的语法不允许这样做。但我确定它不行。另一方面,如果你想要一个字符串输入,我不明白为什么不允许。我会将提取器命名为其他名称。至少在示例中,User非常具有误导性,我更喜欢object NameOfUser {def unapply(s: String): Option[User]...}。我不知道在你的代码中是否有意义。 - Didier Dupont
是的,你说得对。我会给提取器换个名字。但编译器的信息仍然毫无意义。至少应该清楚为什么我不能重载apply以及冲突在哪里。 - Ajay

2

你无法覆盖unapply方法的原因(尤其是)很可能是它与由案例类的伴生对象自动创建的方法具有相同的签名。需要记住,函数的签名不考虑其返回值来进行覆盖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接