在同伴对象中失败适用于mehod

Nic*_*udo 4 scala

Scala类在其伴随对象中拥有apply和使用unapply方法是很常见的.

行为unapply是明确的:如果其参数是或可以转换为类的有效实例,则返回Some它的一个.否则,返回None.

举一个具体的例子,让我们想象一个Url案例类:

object Url {
  def apply(str: String): Url = ??? 
  def unapply(str: String): Option[Url] = ???
}

case class Url(protocol: String, host: String, path: String)
Run Code Online (Sandbox Code Playgroud)

如果str是有效的URL,则unapply返回a Some[Url],否则返回None.

apply但是对我来说有点不太清楚:它应该如何应对str不成为有效的URL?

来自Java世界,我的第一直觉是抛出一个IllegalArgumentException,这将允许我们实现伴侣对象:

object Url {
  def apply(str: String): Url = ... // some function that parses a URI and throws if it fails.

  def unapply(str: String): Option[Url] = Try(apply(str)).toOption
}
Run Code Online (Sandbox Code Playgroud)

我理解这在功能世界中并不被认为是非常好的实践(例如,在这个答案中解释).

另一种方法是apply返回一个Option[Url],在这种情况下,它将是一个简单的克隆,unapply并且最好留下未实现的.

这是正确的结论吗?这类潜在的失败apply方法是否应该实施?在这种情况下,投掷是否正常?我没有看到第三种选择吗?

DCK*_*ing 7

这有点主观,但我认为你不应该这样做.

假设您允许apply失败,即抛出异常或返回空选项.然后做的val url = Url(someString)可能会失败,尽管看起来非常像构造函数.这就是整个问题:apply伴随对象的方法应该可靠地为您构造新实例,并且您无法Url从任意字符串中可靠地构造实例.所以不要这样做.

unapply通常应该用于获取有效Url对象并返回另一个可以Url再次创建的表示.作为一个例子,请查看unapply为case类生成的方法,它只返回一个包含构造它的参数的元组.所以签名应该是def unapply(url: Url): String.

所以我的结论是既不应该用于构建一个Url.我认为有一个方法def parse(str: String): Option[Url]来明确你正在做什么(解析字符串)并且它可能会失败,这将是最惯用的.然后,您可以Url.parse(someString).map(url => ...)使用您的Url实例.

  • @NicolasRinaudo我想是这样,但我已经可以告诉你,如果你不能可靠地进行转换,那么进行隐式转换可能并不明智! (2认同)