【发布时间】:2016-03-11 14:55:56
【问题描述】:
下面的 sn-p 抛出 NullPointerException。 这是 Scala 的预期和正常行为吗?
object ATest extends App {
def getX[T <: X](constr: ⇒ T = null.asInstanceOf[T]): Unit = {
constr
}
getX()
}
class X
从 sn-p 生成(反编译)的 Java 代码:
public final class ATest {
public static void main(String[] arrstring) {
ATest$.MODULE$.main(arrstring);
}
public static void delayedInit(Function0<BoxedUnit> function0) {
ATest$.MODULE$.delayedInit(function0);
}
public static String[] args() {
return ATest$.MODULE$.args();
}
public static void scala$App$_setter_$executionStart_$eq(long l) {
ATest$.MODULE$.scala$App$_setter_$executionStart_$eq(l);
}
public static long executionStart() {
return ATest$.MODULE$.executionStart();
}
public static void delayedEndpoint$test$ATest$1() {
ATest$.MODULE$.delayedEndpoint$test$ATest$1();
}
public static <T extends X> T getX$default$1() {
return ATest$.MODULE$.getX$default$1();
}
public static <T extends X> void getX(Function0<T> function0) {
ATest$.MODULE$.getX(function0);
}
}
public final class ATest$ implements App {
public static final ATest$ MODULE$;
private final long executionStart;
private String[] scala$App$$_args;
private final ListBuffer<Function0<BoxedUnit>> scala$App$$initCode;
public static {
new test.ATest$();
}
public long executionStart() {
return this.executionStart;
}
public String[] scala$App$$_args() {
return this.scala$App$$_args;
}
public void scala$App$$_args_$eq(String[] x$1) {
this.scala$App$$_args = x$1;
}
public ListBuffer<Function0<BoxedUnit>> scala$App$$initCode() {
return this.scala$App$$initCode;
}
public void scala$App$_setter_$executionStart_$eq(long x$1) {
this.executionStart = x$1;
}
public void scala$App$_setter_$scala$App$$initCode_$eq(ListBuffer x$1) {
this.scala$App$$initCode = x$1;
}
public String[] args() {
return App.class.args((App)this);
}
public void delayedInit(Function0<BoxedUnit> body) {
App.class.delayedInit((App)this, body);
}
public void main(String[] args) {
App.class.main((App)this, (String[])args);
}
public <T extends X> void getX(Function0<T> constr) {
constr.apply();
}
public <T extends X> T getX$default$1() {
return null;
}
public final void delayedEndpoint$test$ATest$1() {
this.getX((Function0<T>)new scala.Serializable(){
public static final long serialVersionUID = 0;
public final Nothing. apply() {
return (Nothing.)ATest$.MODULE$.getX$default$1();
}
});
}
private ATest$() {
MODULE$ = this;
App.class.$init$((App)this);
this.delayedInit((Function0<BoxedUnit>)new ATest.delayedInit$body(this));
}
}
public final class ATest$.anonfun extends AbstractFunction0<Nothing.>implements Serializable {
public final Nothing. apply() {
return (Nothing.)ATest$.MODULE$.getX$default$1();
}
}
最后是动作部分:
public <T extends X> void getX(Function0<T> constr) {
constr.apply();
}
public <T extends X> T getX$default$1() {
return null;
}
public final void delayedEndpoint$test$ATest$1() {
this.getX((Function0<T>)new scala.Serializable(){
public final Nothing. apply() {
return (Nothing.)ATest$.MODULE$.getX$default$1();
}
});
}
也就是说:对 getX 的调用传递了新的匿名 Function0,它 apply() 只调用了 null 的 getX$default$1()。所以我看不到任何可以抛出 NPE 的点。
编辑:发现未解决的问题:https://issues.scala-lang.org/browse/SI-8097
编辑:表达式 null.asInstanceOf[T] 为类型 T 生成默认值。如果 Scala 将结果类型 T 推断为 Nothing,我们将使用运行时表达式
null.asInstanceOf[Nothing]
这显然会抛出 Exeption 作为 Nothing is Exception 的默认值。
但是为什么这个 sn-p 只在最后一行抛出 NPE?
object ATest extends App {
def getX[T](x: T = null.asInstanceOf[T]): T = x
getX[Nothing]() // Ok
val x = getX() // Ok
val y = null
println("x= "+x) // prints 'x= null'
println(s"y= $y") // prints 'y= null'
println(s"x= $x") // throws NPE !?
println("x==null ? "+(x==null)) // prints 'x= null'
}
以及为什么这个 sn-p 会抛出 NPE(它与之前的隐式参数不同)?
object ATest extends App {
def getX[T](x: T = null.asInstanceOf[T])(implicit s: String = null): T = x
getX() // throws NPE !?
}
所以情况还很模糊。问题是开放的。
【问题讨论】:
-
我无法使用 Scala 2.11.7 重现 NPE,请参阅 gist.github.com/lrytz/1c05e0fa666b130e2d38 - 你使用的是什么版本?
-
我可以用 Scala 2.11.7 和 Java 1.7 重现这个。
-
噢,我的错,跑错了主目录。
-
该示例在使用 Scala 2.12.0-M3 时不会发生 NPE - 除非我再次出错,欢迎确认!我认为崩溃实际上是正确的(不同的异常可能更有用),并且 2.12.0-M3 可能是错误的。问题是类型检查器为类型参数 T 推断出 Nothing(使用 -Xprint:typer),并且 null 不是 Nothing 类型的有效值(Nothing 没有有效类型)。所以 null.asInstanceOf[Nothing] 崩溃了——它还能做什么?
-
有趣,我可以确认。同样在 repl 中,如果您尝试 "".instanceOf[Nothing],您将不再获得空指针,相反,您会被告知,在 instanceOf 中不能使用 Nothing。看起来他们已经摆脱了该代码,但仍未正确处理该案例。
标签: scala