Scala选项隐式转换-错误做法或缺少功能?

Scala选项隐式转换-错误做法或缺少功能?,scala,implicit-conversion,domain-model,Scala,Implicit Conversion,Domain Model,我将我的数据模型表示为case类,输入的值可以是null作为选项 case class Document(id: Long, title: String, subtitle: Option[String]) 现在我尝试实例化case类: Document(123, "The Title", "Subtitle") // Doesn't work 但是没有!这不起作用,我必须将可选值包装在一个文件中 Document(123, "The Title", Some("Subtitle")) //

我将我的数据模型表示为case类,输入的值可以是null作为选项

case class Document(id: Long, title: String, subtitle: Option[String])
现在我尝试实例化case类:

Document(123, "The Title", "Subtitle") // Doesn't work
但是没有!这不起作用,我必须将可选值包装在一个文件中

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->Some(T)开箱即用,我是唯一一个吗?或者在默认情况下,是否存在任何我不知道的关于在所有地方都有如此广泛的隐式的问题?

这可能会导致数不清的问题。这里的问题不是你可能会想什么,而是你认为不会发生什么。也就是说,如果创建另一个在
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
的类型是
选项[Double]
。您不会期望发生这种情况,但Scala首先对
选项进行隐式转换,然后使用隐式类调用
^
操作符。现在,查看您的代码的人们会挠头,想知道为什么他们会有一个
选项
。您可能会开始看到一些防御性的
x getOrElse 0.0
散布在代码周围,因为人们努力远离
选项(是的,这是个人经验造成的)

也就是说,您应该在对象上使用另一个
apply

object Document{
  def apply(id: Long, title: String, subtitle: String) = new Document(id, title, Some(subtitle))
}

只要没有为
subtitle
定义默认值,即
subtitle:Option[String]=None
这是一个非常危险的实现:

scala> val s: String = null
s: String = null

scala> Document(123, "The Title", s)
res2: Document = Document(123,The Title,Some(null))

前面指出的大多数问题都可以通过对隐式表达式的一个小更改轻松解决:
implict def autoOpt[T](x:T):选项[T]=选项(x)

我真的想不出scala不将此转换作为默认隐式转换器库的一部分的好理由


隐式使代码更难理解这一事实可以作为反对使用任何隐式的论据,但不能作为反对使用这个特定的隐式的论据。带有隐式转换的代码通常难以理解。当您有
选项[Any]
时,这种隐式转换尤其容易混淆,其中
Some(Some(x))
Some(x)
都是有效值。您可以重载
文档。应用
文档。而不应用
。如果您希望您的副标题默认为空字符串,您还可以编写
案例类文档(id:Long,title:string,subtitle:string=“”)
这是真的,在我的常染色体方法中,我应该检查null,在这种情况下返回None