Список 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");