首页 > 解决方案 > 隐式转换和 null

问题描述

以下代码

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

我期望两个 val 都是 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))
    }
  }
}

没有接受 null 的 int 符号方法

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”都被转换为字符串,而不是应用隐式 nullToInt。有人能解释一下编译器是怎么想出来的吗?使用了什么逻辑/工作流程?

另一个问题是是否有办法启用隐式 nullToInt?

PS。我不是在这里谈论最佳实践。随意将问题视为学术兴趣问题。

标签: scalaoperatorsstring-concatenation

解决方案


所以,@AndreyTyukin 说的是对的,机械地我认为还有更多。至于为什么,有两件事正在发生。

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

    implicit final class any2stringadd[A] extends AnyVal

如您所见,any2stringadd负责的是+,您可以在此处看到签名:

def +(other: String): String

更正:没有implicit conversions,比那个更简单

  1. 查看源代码Predef并且any2stringadd确实在起作用的是以下内容

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

String.valueOfof1将返回一个Stringof 1。在 Java 中(并使用 jshell 验证),String添加1到的 anull将变为1null.

jshell> "1" + null
$1 ==> "1null"

推荐阅读