【问题标题】:Could/should an implicit conversion from T to Option[T] be added/created in Scala?是否可以/应该在 Scala 中添加/创建从 T 到 Option[T] 的隐式转换?
【发布时间】:2009-11-17 03:16:22
【问题描述】:

这是一个让事情变得更有效率的机会吗(对于程序员来说):我发现将东西包装在Some 中有点烦人,例如Some(5)。像这样的东西呢:

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

【问题讨论】:

    标签: scala scala-option


    【解决方案1】:

    您会失去一些类型安全性并可能导致混淆。 例如:

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

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

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

    【讨论】:

    • 至少在 IntelliJ IDEA 中,我可以看到某些内容何时自动转换(默认情况下带有下划线)。但也许应该有一种方法来指定隐式转换只在将值传递给方法时发生,而不是在调用方法时发生。
    【解决方案2】:

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

    我的意思是显式隐式不是从TOption[T] 的直接转换,您可以转换到一个包装器对象,它提供了从TOption[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 &lt;: AnyRef - 您应该只对允许null 值的类型进行这种隐式转换,根据定义,这些类型是引用类型。

    【讨论】:

    • 嗨 Flaviu,有趣的建议。我总体上喜欢它 - 虽然我认为它使我的问题变得更糟而不是更好,但现在我不必输入 Some() 我必须输入 toOption... 但它确实具有使用 null 的优势。
    • @flaviu-cipcigan,做同样的事情但更短 - 隐式类 IntWithTimes[T](x: T) { def toOption: Option[T] = if (x != null) Option(x)否则无}
    【解决方案3】:

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

    • 当您需要向类型添加成员时(例如“开放类”;又名“皮条客我的图书馆”模式),转换为扩展 AnyRef 且仅定义您需要的成员。
    • 当您需要“更正”继承层次结构时。因此,您有一些A 类型应该 继承B,但由于某种原因没有。在这种情况下,您可以定义从 AB 的隐式转换。

    这些是 适合定义隐式转换的情况。任何其他转换都会很快遇到类型安全和正确性问题。

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

    【讨论】:

      【解决方案4】:

      在其他开发人员阅读您的代码时,这似乎会让他们感到困惑。

      一般来说,implicit 似乎有助于从一个对象转换到另一个对象,以消除可能使代码混乱的令人困惑的转换代码,但是,如果我有一些变量并且它以某种方式变成了 Some,那么那将好像很麻烦。

      你可能想放一些代码来显示它正在被使用,看看它会有多混乱。

      【讨论】:

      • 我明白你的意思了.. 然而,Option[T] 的要点是它可以保存一个值或一个无,所以对我来说,如果一个方法采用 Option 类型的变量,这似乎很直观[T] 我应该能够将 T 传递给它。你能想出一个你可能会感到困惑的例子吗,例如一个变量不小心变成了 Some?
      【解决方案5】:

      你也可以尝试重载方法:

      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
      }
      

      【讨论】:

        【解决方案6】:

        这对我来说看起来不错,但它可能不适用于原始 T(不能为空)。我猜一个非专业的泛型总是得到盒装的原语,所以可能没问题。

        【讨论】:

          猜你喜欢
          • 2018-10-06
          • 1970-01-01
          • 1970-01-01
          • 2014-03-24
          • 1970-01-01
          • 2016-11-08
          • 2010-10-14
          • 2011-04-04
          • 1970-01-01
          相关资源
          最近更新 更多