可以/应该在Scala中添加/创建从T到Option [T]的隐式转换吗?

时间:2009-11-17 03:16:23

标签: scala scala-option

这是一个让事情变得更有效的机会(对于程序员来说):我发现在Some中包装内容时会有点烦人,例如Some(5)。这样的事情怎么样:

implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)

6 个答案:

答案 0 :(得分:31)

你会失去某种类型的安全性并可能引起混淆。 例如:

  val iThinkThisIsAList = 2 
  for (i <- iThinkThisIsAList) yield { i + 1 }

我(无论出于何种原因)认为我有一个列表,当我迭代它时它没有被编译器捕获,因为它被自动转换为Option [Int]。

我应该补充一点,我认为明确导入这是一个很好的隐含,可能不是全局默认。

答案 1 :(得分:26)

请注意,您可以使用explicit implicit模式,以避免混淆并同时保持代码简洁。

我明确暗示的意思是,而不是从TOption[T]的直接转换,您可以转换为包装器对象,该对象提供了从{{1}进行转换的方法到T

Option[T]

...我可能会找到比class Optionable[T <: AnyRef](value: T) { def toOption: Option[T] = if ( value == null ) None else Some(value) } implicit def anyRefToOptionable[T <: AnyRef](value: T) = new Optionable(value) 更好的名称,但现在您可以编写如下代码:

Optionable

我相信这种方式是完全透明的,有助于理解书面代码 - 以一种很好的方式消除对null的所有检查。

注意val x: String = "foo" x.toOption // Some("foo") val y: String = null x.toOption // None - 您应该只对允许T <: AnyRef值的类型执行此隐式转换,根据定义,这些值是引用类型。

答案 2 :(得分:12)

隐式转换的一般准则如下:

  • 当你需要向一个类型添加成员(一个“开放类”;也就是“pimp my library”模式)时,转换为扩展AnyRef new 类型它只定义了你需要的成员。
  • 当您需要“更正”继承层次结构时。因此,您有一些类型A 应该子类B,但由于某种原因没有。在这种情况下,您可以定义从AB的隐式转换。

这些是情况,适合定义隐式转换。任何其他转换都会匆忙进入类型安全和正确性问题。

T扩展Option[T]实际上没有任何意义,显然转换的目的不仅仅是添加成员。因此,这种转换是不可取的。

答案 3 :(得分:1)

看起来这可能会让其他开发人员感到困惑,因为他们会阅读您的代码。

一般来说,似乎implicit可以帮助从一个对象转换到另一个对象,以减少混乱代码的混乱的代码,但是,如果我有一些变量,它会以某种方式变成{{1}那那似乎很麻烦。

您可能想要显示一些显示正在使用的代码,以查看它会有多混乱。

答案 4 :(得分:0)

您也可以尝试重载该方法:

def having(key:String) = having(key, None)

def having(key:String, default:String) = having(key, Some(default))

def having(key: String, default: Option[String]=Option.empty) : Create = {
  keys += ( (key, default) )
  this
}

答案 5 :(得分:-2)

这对我来说很好,除了它可能不适用于原始T(不能为空)。我猜一个非专业的泛型总是得到盒装基元,所以可能它很好。