Неявные преобразования и нуль - PullRequest
0 голосов
/ 28 сентября 2018

Следующий код

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.

Видимо, первое значение - 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», и «ноль» были преобразованы в строку вместо применения неявного nullToInt.Может кто-нибудь объяснить, , как компилятор придумал это?Какая логика / рабочий процесс использовался?

И еще вопрос , есть ли способ включить implcit nullToInt?

PS.Я не говорю о лучших практиках здесь.Не стесняйтесь рассматривать вопрос как вопрос академического интереса.

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Я попытаюсь ответить на мой собственный вопрос.

Тема немного вводит в заблуждение, и фактически к выражению для val x вообще не применяются неявные преобразования.Null является подтипом String, и Int имеет метод abstract def +(x: String): String, поэтому его можно применять и к Null.

Это также подтверждается выводом Xprint:typer, поскольку он должен показывать всенеявные преобразования и, по-видимому, он ничего не показывает для выражения для x.

. Отвечая на вопросы "есть ли способ включить implcit nullToInt", единственный способ включить это - явно указать в этом случае, потому чтокомпилятор не будет рассматривать использование каких-либо последствий, когда код успешно скомпилирован без них.

0 голосов
/ 28 сентября 2018

Итак, то, что @AndreyTyukin говорит правильно, механически я думаю, что это еще не все.Есть две вещи, которые происходят относительно того, почему.

  1. Any отмечен implicit в Predef, см. Следующее:

    implicit final class any2stringadd[A] extends AnyVal

Как видите, any2stringadd - это то, что отвечает за +, и вы можете увидеть подпись здесь:

def +(other: String): String

Исправление: Нет implicit conversions это было еще проще

Загляните внутрь исходного кода Predef и any2stringadd, который действительно находится в игре, следующее

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, добавленное к null, станет 1null.

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