Scala применяет вызов метода, так как скобки конфликтуют с неявными параметрами

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

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

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

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

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

"Bonjour".sorted.apply(3)

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

("Bonjour".sorted)(3)

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

1 ответ

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

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)Таким образом, вы получаете выгоду от таких преобразований, как неявное приложение.

Другие вопросы по тегам