【问题标题】:Scala Option(null) expected as None but I got Some(0)Scala Option(null) 预期为 None 但我得到了 Some(0)
【发布时间】:2020-03-09 12:23:05
【问题描述】:
val i: java.lang.Integer = null
val o: Option[Int] = Option(i) // This yields Some(0)

null: java.lang.Integer 转换为Scala Option[Int] 的安全方法是什么?

【问题讨论】:

    标签: scala optional scala-java-interop


    【解决方案1】:

    你正在混合 Intjava.lang.Integer 所以

    val i: java.lang.Integer = null
    val o: Option[Int] = Option(i)
    

    隐式转换为

    val o: Option[Int] = Option(Integer2int(i))
    

    变成了

    val o: Option[Int] = Option(null.asInstanceOf[Int])
    

    因此

    val o: Option[Int] = Some(0)
    

    如果你想使用java.lang.Integer,那么写

    val o: Option[java.lang.Integer] = Option(i)
    // o: Option[Integer] = None
    

    【讨论】:

    • 最近有人问过这个问题,所以这是一个真正的问题。也许问题在于推理:Option[Integer](i).map(_.intValue) 对我来说似乎最地道,因为它说明了它在做什么。此外,使用-Xlint 查看val o 的警告!
    • 为了避免拳击往返,`val x: Option[Int] = Option(i).asInstanceOf[Option[Int]]` 其中Integer 被推断出来。
    • 更像forced to :)
    【解决方案2】:

    这似乎正在发生,因为您正在创建Option,并一步将其转换为Int(@MarioGalic 的answer 解释了为什么会发生这种情况)。

    这就是你想要的:

    scala> val o: java.lang.Integer = null
    o: Integer = null
    
    scala> val i: Option[Int] = Option(o).map(_.toInt)
    i: Option[Int] = None
    
    scala> val o1: java.lang.Integer = 1
    o1: Integer = 1
    
    scala> val i1: Option[Int] = Option(o1).map(_.toInt)
    i1: Option[Int] = Some(1)
    

    【讨论】:

    • 在另一个答案中,我建议_.intValue。我猜它只会保存转换调用。
    【解决方案3】:

    之前也遇到过同样的问题。 Scala 团队知道这种可疑行为。 似乎改变它会破坏其他地方的东西。 见https://github.com/scala/bug/issues/11236https://github.com/scala/scala/pull/5176

    【讨论】:

    • 真正有问题的行为是将null 视为一个整数。这大概是 C 的后遗症,可以将 0 分配给指针。但这并不意味着生成的指针是0,所以即使在C 中也不能在两者之间切换。
    • Integer 很可能来自 Java 代码,因此“不要将 null 视为整数”不是一个可行的建议。我们使用Option.apply 明确检查此整数的可空性。所以我们得到了意外的输出,没有明确地执行任何不安全的操作。
    • 关键是当根本原因是 Java 时,你不能责怪 Scala 的“可疑行为”。可行的建议是从 Java 类型显式转换为等效的 Scala 类型,而不是使用隐式转换。 (因此JavaConverters 而不是JavaConversion
    • 好吧,我可以而且我确实责怪 Scala 在这种情况下没有发出编译错误/警告。甚至运行时崩溃也会更好。即使仅在我的公司中,就有 2 名拥有 5 年以上 Scala 经验的开发人员遇到了这个问题。
    • @Tim 很容易导致运行时崩溃,只需调用theInteger.intValue()。避免这种崩溃需要额外的运行时检查。在旧版本的 Scala 中,这种转换确实产生了 NPE。它被报告为错误,并已修复为当前行为。我不是 Scala 专家,但我挖掘了 scala-dev#355scala#5176 作为历史背景。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    相关资源
    最近更新 更多