在 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。>
答案 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
类型,并且它是否为trait
,class
以及内部内容对于您的API用户而言应该无关紧要。您也可以编写type Email = String
,但类型别名不是“ newtype”,因此可以在其中放置任何String
,这样编译器将无法使用。是否需要由您决定。