隐式转换和空值

时间:2018-09-28 16:45:36

标签: scala operators string-concatenation

以下代码

import scala.language.implicitConversions

object myObj {
  implicit def nullToInt(x: Null) = 0

  def main(args: Array[String]): Unit = {
    val x = 1 + null
    val y = 1 + nullToInt(null)

    println(x + " " + y)
  }
}

给出低于结果的结果

1null 1

我期望两个值都为Int且等于1。

显然,第一个val是String,等于“ 1null”。

Xprint:typer显示源代码已翻译成

package <empty> {
  import scala.language.implicitConversions;
  object myObj extends scala.AnyRef {
    def <init>(): myObj.type = {
      myObj.super.<init>();
      ()
    };
    implicit def nullToInt(x: Null): Int = 0;
    def main(args: Array[String]): Unit = {
      val x: String = 1.+(null);
      val y: Int = 1.+(myObj.this.nullToInt(null));
      scala.Predef.println(x.+(" ").+(y))
    }
  }
}

没有用于int的符号方法可以接受null

scala> 10+null
res0: String = 10null

scala> 10*null
<console>:12: error: overloaded method value * with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (Null)
       10*null
         ^

scala> 10-null
<console>:12: error: overloaded method value - with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (Null)
       10-null
         ^

我假设“ 1”和“ null”都被转换为String,而不是应用隐式nullToInt。有人可以解释编译器是如何想到的吗?使用了什么逻辑/工作流程?

另一个问题是是否有一种启用隐式nullToInt的方法?

PS。我不是在这里谈论最佳实践。可以根据学术兴趣随意考虑问题。

2 个答案:

答案 0 :(得分:3)

所以,@ AndreyTyukin所说的是对的,从机械上来说,我认为还有更多。关于原因,有两件事正在发生。

  1. Anyimplicit中用Predef装饰,请参见以下内容:

    implicit final class any2stringadd[A] extends AnyVal

如您所见,any2stringadd+的责任,您可以在此处查看签名:

def +(other: String): String

更正:没有implicit conversions,它甚至更简单

  1. 下面是确实在起作用的Predefany2stringadd的源代码中

implicit final class any2stringadd[A](private val self: A) extends AnyVal { def +(other: String): String = String.valueOf(self) + other }

String.valueOf中的

1将返回String中的1。在Java中(并使用jshell进行验证),添加到String的{​​{1}}中的1将成为null

1null

答案 1 :(得分:3)

我会尝试回答我自己的问题。

主题有点误导,实际上,根本没有将隐式转换应用于val x的表达式。 NullString的子类型,并且Int具有方法abstract def +(x: String): String,因此它也可以应用于Null。

Xprint:typer的输出也证实了这一点,因为它应该显示所有隐式转换,并且显然不显示任何x表达式。

回答问题“是否有启用隐式nullToInt的方法”,在这种情况下,启用它的唯一方法是显式指定,因为在没有它们的情况下成功编译代码时,编译器将不考虑使用任何隐式。