Scala применяет вызов метода, так как скобки конфликтуют с неявными параметрами - PullRequest
0 голосов
/ 09 мая 2018

В книге Кея Хорстмана "Scala для нетерпеливых" есть примечание о методе применения:

Иногда нотация () конфликтует с другой функцией Scala: неявными параметрами.Например, выражение "Bonjour".sorted(3) выдает ошибку, потому что отсортированный метод может быть вызван с упорядочением, но не является допустимым упорядочением 3.

Решение состоит в том, чтобы назначить "Bonjour".sortedпеременная и вызов применяются к ней, например:

val result = "Bonjour".sorted
result(3)

Или вызов применяется явно:

"Bonjour".sorted.apply(3)

Но почему это не работает и приводит к ошибке компиляции:

("Bonjour".sorted)(3)

Сортированный метод возвращает String, который может быть неявно преобразован в StringOps, а скобки используются для переноса строкового выражения.Почему компилятор не принимает вызов метода apply для StringOps?

1 Ответ

0 голосов
/ 09 мая 2018

Вы можете использовать -Xprint:parser, чтобы увидеть, что парены сбрасываются раньше:

scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x

scala> "hi".scaled(5)
res0: String = hihihihihi

scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi

scala> "hi".scaled(5)(3)
res2: Char = i

scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi

scala> :se -Xprint:parser

scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of                    parser]] // <console>
package $line8 {
  object $read extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    object $iw extends scala.AnyRef {
      def <init>() = {
        super.<init>();
        ()
      };
      import $line3.$read.$iw.$iw.x;
      object $iw extends scala.AnyRef {
        def <init>() = {
          super.<init>();
          ()
        };
        val res4 = {
          implicit val n: Int = 5;
          "hi".scaled(3)
        }
      }
    }
  }
}

res4: String = hihihi

scala> 

Дополнительные парены ничего не делают. Компилятор просто видит приложение expr(args). Поскольку это приложение, вы не получаете преобразование «неявное приложение».

В любом случае значение scaled, метода, зависит от ожидаемого типа.

Причина, по которой мы ожидаем, что дополнительные парены будут иметь значение, состоит в том, что парены переопределяют приоритет операторов. Но (x) это просто x.

Возможно, спецификация на самом деле ясна по этому поводу:

e(args) требует, чтобы e был применим к args. В частности, аргументы проверяются по типу в соответствии с типами параметров e.

e(args) принимается как e.apply(args), если e является значением, но scaled является методом.

Вы надеетесь, что «неявное приложение» вставит неявные аргументы, но это применимо, только если e еще не применено. Или что (e)(args) можно принять за (e(_))(args), то есть (x => e(x))(arg).

Если записано как e.apply(arg), e не является приложением, подобным e(arg), поэтому вы получаете выгоду от преобразований, таких как неявное приложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...