这是一个让事情变得更有效率的机会吗(对于程序员来说):我发现必须将东西包装Some
在Some(5)
. 像这样的东西怎么样:
implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
这是一个让事情变得更有效率的机会吗(对于程序员来说):我发现必须将东西包装Some
在Some(5)
. 像这样的东西怎么样:
implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
您将失去一些类型安全性并可能导致混淆。例如:
val iThinkThisIsAList = 2
for (i <- iThinkThisIsAList) yield { i + 1 }
我(无论出于何种原因)认为我有一个列表,当我迭代它时它没有被编译器捕获,因为它被自动转换为 Option[Int]。
我应该补充一点,我认为这是显式导入的一个很好的暗示,可能不是全局默认值。
请注意,您可以使用显式隐式模式,这将避免混淆并同时保持代码简洁。
我的意思是显式隐式不是直接转换 from T
toOption[T]
你可以转换为包装器对象,它提供了从T
to转换的方法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
,但现在您可以编写如下代码:
val x: String = "foo"
x.toOption // Some("foo")
val y: String = null
x.toOption // None
我相信这种方式是完全透明的,有助于理解书面代码——以一种很好的方式消除所有对 null 的检查。
请注意T <: AnyRef
- 您应该只对允许值的类型进行这种隐式转换null
,根据定义,这些值是引用类型。
隐式转换的一般准则如下:
AnyRef
并且只定义您需要的成员。A
应该有subclassed B
,但由于某种原因没有。A
在这种情况下,您可以定义从to的隐式转换B
。这些是唯一适合定义隐式转换的情况。任何其他转换都会很快遇到类型安全和正确性问题。
T
extend确实没有任何意义Option[T]
,显然转换的目的不仅仅是添加成员。因此,这种转换是不可取的。
看起来这可能会让其他开发人员在阅读您的代码时感到困惑。
一般来说,它似乎implicit
有助于从一个对象转换到另一个对象,以消除可能使代码混乱的令人困惑的转换代码,但是,如果我有一些变量并且它以某种方式变成了一个Some
那么这似乎很麻烦。
你可能想放一些代码来显示它正在被使用,看看它会有多混乱。
您也可以尝试重载该方法:
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
}
这对我来说看起来不错,但它可能不适用于原始 T (不能为空)。我猜一个非专业的泛型总是得到盒装的原语,所以可能没问题。