我将我的数据模型表示为案例类,键入的值可能为null。
case class Document(id: Long, title: String, subtitle: Option[String])
现在我尝试实例化案例类:
Document(123, "The Title", "Subtitle") // Doesn't work
但是NOPE!这不起作用,我必须将可选值包装在Some中。
Document(123, "The Title", Some("Subtitle")) // Works
Scala对于类型一般非常聪明,但为什么硬编码文字或(任何字符串)与null / None不同,这是不言自明的?
我能够解决这个问题并让Scala更聪明"通过添加此隐式转换
implicit def autoSome[T](any:T) = Some(any)
Document(123, "The Title", "Subtitle") // Now it works!
问题:我是唯一一个应该提供隐式转换的语言T - >一些(T)开箱即用?或者是否有任何问题我都不知道默认情况下是否存在如此广泛的含义?
答案 0 :(得分:5)
这会导致无数问题。这里的问题不是你可能想到的,而是你认为不会发生的事情。也就是说,如果你创建另一个适用于Option
类型的隐式类,你最终可能会创建一个你从未打算过的人为结果,即你的重载类型的运算符出现在你的非重载类型中。
implicit class OptDouble(opt: Option[Double]) extends Any{
def *(x: Double) = Some((opt getOrElse 0.0) * x)
def ^(x: Double) = Some(Math.power(opt getOrElse 1.0, x))
}
val z = q^4.5
z
的类型为Option[Double]
。您不希望发生这种情况,但首先Scala执行了隐式转换为Option
,然后使用隐式类调用^
运算符。现在,看着你的代码的人们会不知道为什么他们有Option
。你可能会开始在代码周围看到一些防御x getOrElse 0.0
,因为人们会争取保持Option
(并且是的,这来自个人经验。)
那就是说,你应该做的是在对象上使用另一个apply
:
object Document{
def apply(id: Long, title: String, subtitle: String) = new Document(id, title, Some(subtitle))
}
只要您没有为subtitle
定义默认值,即subtitle: Option[String] = None
,就会执行您希望它执行的所有操作。
答案 1 :(得分:4)
前面提到的大多数问题很容易通过对隐式的一个小改动来修复:
implict def autoOpt[T](x: T): Option[T] = Option(x)
我无法想到一个很好的理由scala不会将此转换作为隐式转换器的默认库的一部分提供。
这意味着使代码更难理解的事实可以用作反对使用任何隐式的参数,但不能反对使用这个特定的
答案 2 :(得分:1)
这是一个非常危险的实施:
scala> val s: String = null
s: String = null
scala> Document(123, "The Title", s)
res2: Document = Document(123,The Title,Some(null))