为什么以及如何将案例类迁移到Scala中的提取器

时间:2019-06-05 19:41:25

标签: scala pattern-matching case-class extractor

Scala编程讨论中,何时使用案例类以及何时使用提取器,他们说

  

提取程序破坏了数据表示形式和模式之间的链接...此属性称为表示形式独立性 ...

     

如果您的组件已定义并导出了一组案例类,那么您将被困在其中,因为客户端代码可能已经包含针对这些类的模式匹配...

     

幸运的是,您无需立即决定。您总是可以从案例类开始,然后,如果需要,可以更改为提取器。由于提取器上的模式和案例类上的模式在Scala中看起来完全一样,因此客户端中的模式匹配将继续起作用。

我试图弄清楚它是什么样的。假设以他们的示例为例,我使用

case class Email(user: String, domain: String)

我和客户Bob和我俩都像这样

def send(addr: Email) = addr match {
  case Email(user, domain) => ...
}

send(Email("joel", "gmail.com"))

然后假设我决定切换到提取器以获取表示独立性

// case class Email(user: String, domain: String)

object Email {
  def apply(user: String, domain: String) = user + "@" + domain

  def unapply(addr: String) = addr split "@" match {
    case Array(user: String, domain: String) => Some(user, domain)
    case _ => None
  }
}

这一切正常,除了send中的编译失败:“未找到:键入电子邮件”。我可以用

解决
type Email = String

但这是正确的方法吗?而且我不太了解这如何帮助我获得代表独立性。当然,鲍勃可以"joel@gmail.com"Email("joel", "gmail.com")(现在等效)匹配,但我必须假定它们正在使用Email s。

1 个答案:

答案 0 :(得分:0)

我假设表示独立性意味着您可以按照自己想要的方式将内容存储在Email中,但是您仍然需要使用这种单独的类型Email ...如果您想从Email返回apply并在unapply中提取它:

class Email(private val internal: String)

object Email {
  def apply(user: String, domain: String): Email = new Email(user + "@" + domain)

  def unapply(email: Email): Option[(String, String)] =
    email.internal split "@" match {
      case Array(user: String, domain: String) => Some((user, domain))
      case _                                   => None
    }
}

这样您就可以写:

val email: Email = Email("my", "email.com")

email match {
  case Email(user, domain) => ...
}

,同时可以根据自己的喜好更改Email的内部。但是,仍然必须有一些Email类型,并且它是否为traitclass以及内部内容对于您的API用户而言应该无关紧要。您也可以编写type Email = String,但类型别名不是“ newtype”,因此可以在其中放置任何String,这样编译器将无法使用。是否需要由您决定。