23

我一直想知道透明 implicit转换是否真的是一个好主意,以及更多地,嗯,显式地使用隐式是否真的更好。例如,假设我有一个接受 aDate作为参数的方法,并且我有一个将 a 转换String为 a的隐式转换Date

implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s)

private def foo(d: Date)

然后显然我可以通过透明implicit转换来调用它:

foo("20090910")

让我将字符串转换为日期这一事实更明确会更好吗?

class DateString(val s: String) { 
  def toDate : Date = new SimpleDateFormat("yyyyMMdd").parse(s) 
}

implicit def str2datestr(s: String) : DateString = new DateString(s)

那么用法看起来更像:

foo("20090910".toDate)

implicit这样做的好处是,以后会更清楚地知道发生了什么——我现在已经被我应该知道的透明转换(Option对任何人?)抓到了几次,Iterable而且这种用法仍然允许我们利用implicits。

4

2 回答 2

44

我相信在可读性方面,进行隐式转换的更“显式”的方式比完全透明的方式要好得多,至少在这个例子中是这样。

在我看来,从一个类型到另一个类型implicit完全透明地使用 s是可以的,因为您总是可以将一个类型的对象视为能够在需要类型对象的任何时候使用的。例如,a到 a的隐式转换总是有意义的 - 从概念上讲,a 总是可以被视为一个字符序列(例如,在 C 中,字符串只是一个字符序列)。对所有s的调用都有意义。ABABStringRandomAccessSeq[Char]Stringx.foreach(println) String

另一方面,当类型对象有时A可以用作类型对象时,应该使用更显式的转换。在您的示例中,调用没有意义并引发错误。由于 Scala 没有检查异常,因此调用明确表示可能抛出异常(可能不是有效日期)。此外,显然看起来是错误的,而您需要查阅文档以了解为什么可能是错误的。Scala 标准库中的一个例子是从s 到s 的转换,通过wrapper 的方法(s可以被视为s,但并非总是如此)。Bfoo("bar")foo(s.toDate)sfoo("bar".toDate)foo("bar")StringInttoIntRichStringStringInt

于 2009-09-10T12:47:57.390 回答
13

当您进行从 X 到 Y 的隐式转换(如上面从 String 到 Date 的转换)时,您实质上是在说,如果您一开始就可以完全控制 X 的编写,您就会使 X 实现或成为Y 的子类。

如果 X 实现 Y 有意义,则添加转换。如果没有,那可能是不合适的。例如,String 实现 RandomAccessSeq[Char] 是有意义的,但 String 实现 Date 可能没有意义(尽管 String 实现 StringDate 似乎很好)。

(我有点晚了,Flaviu 有一个很好的答案,但我想补充一下我对隐式的看法。)

于 2009-09-12T22:04:33.403 回答