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