Список Scala "магических" функций
Где я могу найти список Scala "магических" функций, таких как apply
, unapply
, update
, +=
и т.д.?
По волшебным функциям я подразумеваю функции, которые используются синтаксическим сахаром компилятора, например
o.update(x,y) <=> o(x) = y
Я искал какую-то комбинацию scala
magic
и синонимы functions
, но ничего не нашел.
Меня не интересует использование магических функций в стандартной библиотеке, но в которых существуют магические функции.
Ответы
Ответ 1
Насколько я знаю:
Связанные с Getters/seters:
apply
update
identifier_=
Соответствие шаблону:
unapply
unapplySeq
For-постижений:
map
flatMap
filter
withFilter
foreach
Префиксные операторы:
unary_+
unary_-
unary_!
unary_~
Кроме того, любое неявное из A в B. Scala также преобразует A <op>= B
в A = A <op> B
, если прежний оператор не определен, "op" не является буквенно-цифровым, а <op>=
не является !=
, ==
, <=
или >=
.
И я не верю, что там есть какое-то место, где перечислены синтаксические сахара Scala.
Ответ 2
В дополнение к update
и apply
также существует ряд унарных операторов, которые (я считаю) квалифицируются как магические:
-
unary_+
-
unary_-
-
unary_!
-
unary_~
Добавьте к этому обычные операторы infix/suffix (которые могут быть почти любыми), и у вас есть полный пакет.
Вам действительно стоит взглянуть на Scala Language Specification. Это единственный авторитетный источник в этом материале. Это не так сложно читать (до тех пор, пока вам удобнее использовать контекстно-свободные грамматики) и очень легко доступны для поиска. Единственное, что он не уточняет, это поддержка XML.
Ответ 3
Извините, если он точно не отвечает на ваш вопрос, но мой любимый момент WTF до сих пор является @как оператор присваивания внутри шаблона. Благодаря мягкой копии "Программирование в Scala" я узнал, что это было довольно быстро.
Используя @, мы можем привязать любую часть шаблона к переменной, и если совпадение шаблона будет успешным, переменная будет захватывать значение подматрицы. Вот пример из Программирование в Scala (раздел 15.2 - Переменная привязка):
expr match {
case UnOp("abs", e @ UnOp("abs", _)) => e
case _ =>
}
Если совпадение всего шаблона выполнено успешно, затем часть, которая соответствовала Доступна опция UnOp ( "abs", _) как переменная e.
И здесь, о чем говорит Программирование Scala.
Ответ 4
Они определены в языковой спецификации Scala.
Насколько мне известно, есть три "волшебные" функции, о которых вы говорили.
Scalas Getter и Setter могут также относиться к вашей "магии":
scala> class Magic {
| private var x :Int = _
| override def toString = "Magic(%d)".format(x)
| def member = x
| def member_=(m :Int){ x = m }
| }
defined class Magic
scala> val m = new Magic
m: Magic = Magic(0)
scala> m.member
res14: Int = 0
scala> m.member = 100
scala> m
res15: Magic = Magic(100)
scala> m.member += 99
scala> m
res17: Magic = Magic(199)
Ответ 5
Я также добавлю _*
для сопоставления шаблонов на произвольное количество параметров, таких как
case x: A(_*)
И правило ассоциативности операторов, из книги Odersky-Spoon-Venners:
Ассоциативность оператора в Scala определяется его последним персонаж. Как упоминалось в <... > , любой метод, который заканчивается в символе ':' вызывается в его правом операнде, проходя в левый операнд. Методы, которые заканчиваются любым другим персонажем, - это другие наоборот. Они вызывается в их левом операнде, проходя в правый операнд. Таким образом, a * b дает a. * (B), но a: b дает b.:( a).
Возможно, мы также должны упомянуть синтаксический desugaring для выражений, которые можно найти здесь
И (конечно!), альтернативный синтаксис для пар
a -> b //converted to (a, b), where a and b are instances
(как правильно указано, это просто неявное преобразование, выполняемое через библиотеку, поэтому оно, вероятно, не подходит, но я нахожу его общей головоломкой для новичков)
Ответ 6
Я хотел бы добавить, что есть также "магическая" черта - scala.Dynamic
:
Маркерный признак, который позволяет динамические вызовы. Экземпляры x
этого признака допускают вызовы метода x.meth(args)
для произвольных имен методов meth
и списков аргументов args
, а также для доступа к полю x.field
для произвольных имен полей field
.
Если вызов не поддерживается на основе x
(т.е. если проверка типа не выполняется), он переписывается в соответствии со следующими правилами:
foo.method("blah") ~~> foo.applyDynamic("method")("blah")
foo.method(x = "blah") ~~> foo.applyDynamicNamed("method")(("x", "blah"))
foo.method(x = 1, 2) ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2))
foo.field ~~> foo.selectDynamic("field")
foo.varia = 10 ~~> foo.updateDynamic("varia")(10)
foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13)
foo.arr(10) ~~> foo.applyDynamic("arr")(10)
Как и в случае с Scala 2.10, определение прямых или косвенных подклассов этого признака возможно только в том случае, если динамика характеристик языка включена.
Итак, вы можете делать такие вещи, как
import scala.language.dynamics
object Dyn extends Dynamic {
def applyDynamic(name: String)(a1: Int, a2: String) {
println("Invoked " + name + " on (" + a1 + "," + a2 + ")");
}
}
Dyn.foo(3, "x");
Dyn.bar(3, "y");