【问题标题】:Scala named arguments with default (generics type) arguments具有默认(泛型类型)参数的 Scala 命名参数
【发布时间】:2015-12-09 13:27:40
【问题描述】:

在下面的scala代码中,NullPointerException在第3个方法调用的入口处被抛出。我检查了字节码。似乎,在f(1, c=2) 中,编译器在f$default$2 的返回值上插入了一个检查转换,它将b 的类型转换为Nothing。但是在f(1) 中,编译器不进行这种转换。为什么?

import scala.reflect.ClassTag
import scala.reflect._
object test {
    def f[T : ClassTag](a:T, b:T=null.asInstanceOf[T], c:Int=2)={ print("*"+classTag[T]+"*");println(a, b, c) }
    def main(args: Array[String]) {
        f(1)
        f(1, 2)
        f(1, c=3) //Null pointer!! But why f(1) is right? 
    }
}

【问题讨论】:

    标签: java scala


    【解决方案1】:

    很难推断编译器何时应用或不应用运行时检查,我将留给一些编译器专家,但.asinstanceOf 很可能在类型参数无限制时应用Nothing 时发送错误。

    所以一般规则 - 在所有可能的情况下尝试摆脱 .asInstanceOf

    对于您的方法,一个合法的定义可能是

    def f[T >: Null : ClassTag](a: T, b: T = null, c: Int = 2) = { ... }
    

    【讨论】:

    • 一个很好的一般规则。我总结了一个一般规则,即永远不要在默认参数的默认值中使用泛型类型。但是,我不能再举其他例子来支持这种说法:)
    【解决方案2】:

    null.asInstanceOf 是个坏主意,无论如何(永远不要投射空值!)。 删除它确实修复了 NPE,但 ClasTag 变为 Nothing

    在这种情况下,运行时似乎正在尝试使用第二个参数来提取 ClassTag 并且失败了。现在,为什么在这种情况下会这样做,而不是第一种情况f(1),我不知道。 有趣的是,f(1, null.asInstanceOf[Int], 3) 也有效,所以问题一定与解决默认参数的方式有关。

    你也可以f[Int](1, c=3)。这行得通。

    更好的是,完全避免使用空值。这是斯卡拉。 null 引用有点像 java 中的 goto:你可以使用它,但真的,真的,真的不应该。

    【讨论】:

    • 非常感谢。你的意思是在这种情况下我应该一直使用 Option 的 None 而不是 null?
    • 差不多。而不仅仅是“在这种情况下”——总是如此。 Scala 中甚至存在 null 的唯一原因是与 Java 的互操作性。否则没有什么好的用途。
    猜你喜欢
    • 2018-02-18
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多