Что означают все символические операторы Scala?
синтаксис Scala имеет много символов. Поскольку эти типы имен трудно найти с помощью поисковых систем, полный список из них было бы полезно.
каковы все символы в Scala, и что делает каждый из них?
в частности, я хотел бы знать, о ->,||=,++=,<=,_._,:: и :+=.
9 ответов:
я разделяю операторов, с целью обучения, на четыре категории:
- ключевые слова/зарезервированные символы
- автоматически импортируемые методы
- общие методы
- синтаксический сахар/состав
хорошо, что большинство категорий представлены в вопросе:
-> // Automatically imported method ||= // Syntactic sugar ++= // Syntactic sugar/composition or common method <= // Common method _._ // Typo, though it's probably based on Keyword/composition :: // Common method :+= // Common methodточное значение большинства из этих методов зависит от класса, определяя их. Например,
<=onIntозначает "меньше или равно". Первый,->, я приведу в качестве примера ниже.::вероятно, это метод, определенный наList(хотя может быть объект с тем же именем), и:+=вероятно, это метод, определенный на различныхBufferклассы.Итак, давайте посмотрим их.
ключевые слова/зарезервированные символы
есть некоторые символы в Scala, которые специальный. Два из них считаются правильными ключевыми словами, в то время как другие просто "зарезервированы". Они таковы:
// Keywords <- // Used on for-comprehensions, to separate pattern from generator => // Used for function types, function literals and import renaming // Reserved ( ) // Delimit expressions and parameters [ ] // Delimit type parameters { } // Delimit blocks . // Method call and path separator // /* */ // Comments # // Used in type notations : // Type ascription or context bounds <: >: <% // Upper, lower and view bounds <? <! // Start token for various XML elements " """ // Strings ' // Indicate symbols and characters @ // Annotations and variable binding on pattern matching ` // Denote constant or enable arbitrary identifiers , // Parameter separator ; // Statement separator _* // vararg expansion _ // Many different meaningsэто все часть языка, и, как таковой, можно найти в любом тексте, который правильно описывает язык, например Спецификация Scala(формат PDF) сам.
последнее, подчеркивание, заслуживает особого описания, потому что оно так широко используется и имеет так много разных значений. Вот пример:
import scala._ // Wild card -- all of Scala is imported import scala.{ Predef => _, _ } // Exception, everything except Predef def f[M[_]] // Higher kinded type parameter def f(m: M[_]) // Existential type _ + _ // Anonymous function placeholder parameter m _ // Eta expansion of method into method value m(_) // Partial function application _ => 5 // Discarded parameter case _ => // Wild card pattern -- matches anything f(xs: _*) // Sequence xs is passed as multiple parameters to f(ys: T*) case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequenceя, наверное, забыл какой-то другой смысл, хотя.
автоматически импортируемые методы
Итак, если вы не нашли символ, который вы ищете в списке выше, то это должен быть метод или часть одного. Но, часто, вы увидите какой-то символ и документация для класса не будет иметь этот метод. Когда это происходит, либо вы смотрите на композицию одного или нескольких методов с чем-то другим, либо метод был импортируется в область видимости или доступен через импортированное неявное преобразование.
эти еще можно найти on ScalaDoc: вы просто должны знать, где их искать. Или, в противном случае, посмотрите на индекс (в настоящее время сломан на 2.9.1, но доступен на ночь).
каждый код Scala имеет три автоматических импорта:
// Not necessarily in this order import _root_.java.lang._ // _root_ denotes an absolute path import _root_.scala._ import _root_.scala.Predef._первые два делают доступными только классы и одноэлементные объекты. Третий содержит все неявные преобразования и импортированные методы, так как
Predefэто сам объект.заглянув внутрь
Predefбыстро показать некоторые символы:class <:< class =:= object <%< object =:=любой другой символ будет доступен через неявное преобразование. Просто посмотрите на методы, помеченные
implicitчто получать в качестве параметра объект типа, который получает метод. Например:"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameterв приведенном выше случае,
->is определено в классеArrowAssocметодомany2ArrowAssocчто принимает объект типаA, гдеAявляется неограниченным параметром типа для того же метода.общие методы
Итак, многие символы-это просто методы в классе. Например, если вы делаете
List(1, 2) ++ List(3, 4)вы найдете способ
++прямо на ScalaDoc для список. Тем не менее, есть одно соглашение, которое вы должны знать при поиске методы. Методы, заканчивающиеся двоеточием (:) привязать справа вместо левой. Другими словами, в то время как приведенный выше вызов метода эквивалентен:List(1, 2).++(List(3, 4))если бы я имел, вместо
1 :: List(2, 3), что было бы эквивалентно:List(2, 3).::(1)поэтому вам нужно посмотреть на найденный тип справа при поиске методов, заканчивающихся двоеточием. Рассмотрим, например:
1 +: List(2, 3) :+ 4первый метод (
+:) привязывается справа, а находится наList. Второй способ (:+) - это просто обычный метод, и привязывается слева-опять же, наList.синтаксический сахар/состав
Итак, вот несколько синтаксических сахаров, которые могут скрывать метод:
class Example(arr: Array[Int] = Array.fill(5)(0)) { def apply(n: Int) = arr(n) def update(n: Int, v: Int) = arr(n) = v def a = arr(0); def a_=(v: Int) = arr(0) = v def b = arr(1); def b_=(v: Int) = arr(1) = v def c = arr(2); def c_=(v: Int) = arr(2) = v def d = arr(3); def d_=(v: Int) = arr(3) = v def e = arr(4); def e_=(v: Int) = arr(4) = v def +(v: Int) = new Example(arr map (_ + v)) def unapply(n: Int) = if (arr.indices contains n) Some(arr(n)) else None } val Ex = new Example // or var for the last example println(Ex(0)) // calls apply(0) Ex(0) = 2 // calls update(0, 2) Ex.b = 3 // calls b_=(3) // This requires Ex to be a "val" val Ex(c) = 2 // calls unapply(2) and assigns result to c // This requires Ex to be a "var" Ex += 1 // substituted for Ex = Ex + 1последнее интересно, потому что любой символьный метод может быть объединен для формирования метода, подобного присваиванию.
и, конечно, есть различные комбинации, которые могут появиться в код:
(_+_) // An expression, or parameter, that is an anonymous function with // two parameters, used exactly where the underscores appear, and // which calls the "+" method on the first parameter passing the // second parameter as argument.
одна (хорошая, IMO) разница между Scala и другими языками заключается в том, что она позволяет вам называть ваши методы почти любым символом.
то, что вы перечисляете, - это не "пунктуация", а простые и простые методы, и поэтому их поведение варьируется от одного объекта к другому (хотя есть некоторые соглашения).
например, регистрация Scaladoc документация для List, и вы увидите некоторые из методов, которые вы упомянули здесь.
некоторые вещи имейте в виду:
в большинстве случаев
A operator+equal Bсочетание переводится какA = A operator B, как в||=или++=примеры.методы, которые заканчиваются на
:являются правильными ассоциативными, это означает, чтоA :: Bна самом делеB.::(A).вы найдете большинство ответов, просмотрев документацию Scala. Сохранение ссылки здесь будет дублировать усилия, и она быстро отстает:)
вы можете сгруппировать их в первую очередь в соответствии с некоторыми критериями. В этом посте я просто объясню символ подчеркивания и стрелку вправо.
_._содержит период. Точка в Scala всегда указывает на вызов метода. Таким образом, слева от периода у вас есть получатель, а справа от него сообщение (имя метода). Сейчас_это специальный символ в Scala. Есть несколько сообщений об этом, например эта запись в блоге все использовать случаи. Вот это анонимная функция short cut, что это ярлык для функции, которая принимает один аргумент и вызывает метод_на нем. Сейчас_не является допустимым методом, так что, безусловно, вы видели_._1или что-то подобное, то есть вызов метода_._1на аргумент функции._1до_22являются методы кортежей, которые извлекают определенный элемент кортежа. Пример:val tup = ("Hallo", 33) tup._1 // extracts "Hallo" tup._2 // extracts 33теперь давайте предположим вариант использования для функция ярлык приложения. Дано отображение, которое отображает целые числа в строки:
val coll = Map(1 -> "Eins", 2 -> "Zwei", 3 -> "Drei")ВООП, есть уже другое появление странной пунктуации. Дефис и больше-чем символы, которые напоминают стрелка вправо, является оператором, который производит
Tuple2. Так что нет никакой разницы в результате написания либо(1, "Eins")или1 -> "Eins", только что последний легче читать, особенно в списке кортежей, как на карте образец. Элемент->- это не магия, это, как и несколько других операторов, у нас все подразумевается преобразования в объектеscala.Predefв область. Преобразование, которое происходит здесьimplicit def any2ArrowAssoc [A] (x: A): ArrowAssoc[A]здесь
ArrowAssocимеет->метод, который создаетTuple2. Таким образом1 -> "Eins"актуален вызовPredef.any2ArrowAssoc(1).->("Eins"). Ладно. Теперь вернемся к исходному вопросу с символом подчеркивания:// lets create a sequence from the map by returning the // values in reverse. coll.map(_._2.reverse) // yields List(sniE, iewZ, ierD)подчеркивание здесь сокращает следующий эквивалентный код:
coll.map(tup => tup._2.reverse)отметим, что
mapметод карты передает кортеж ключа и значения аргументу функции. Поскольку нас интересуют только значения (строки), мы извлекаем их с помощью_2метод на кортеже.
в дополнение к блестящим ответам Даниила и 0__, я должен сказать, что Scala понимает Unicode аналоги для некоторых символов, так вместо
for (n <- 1 to 10) n % 2 match { case 0 => println("even") case 1 => println("odd") }можно писать
for (n ← 1 to 10) n % 2 match { case 0 ⇒ println("even") case 1 ⇒ println("odd") }
<=так же, как вы бы "прочитали" его: "меньше или равно". Так что это математический оператор, в списке<(меньше?),>(больше?),==(равных?),!=(Не равно?),<=(меньше или равно?), и>=(больше или равно?).это не должно быть перепутал С
=>что-то вроде двойная стрелка вправо, используется для отделения списка аргументов от тела a функция и отделить условие испытаний в сопоставлении с образцом (acaseblock)из тела, выполненного при совпадении. Вы можете увидеть пример этого в моих предыдущих двух ответах. Во-первых, использование функции:coll.map(tup => tup._2.reverse)который уже сокращен, поскольку типы опущены. Следующая функция будет
// function arguments function body (tup: Tuple2[Int, String]) => tup._2.reverseи использование сопоставления с образцом:
def extract2(l: List[Int]) = l match { // if l matches Nil return "empty" case Nil => "empty" // etc. case ::(head, Nil) => "exactly one element (" + head + ")" // etc. case ::(head, tail) => "more than one element" }
о
::есть еще Stackoverflow запись, которая охватывает::случае. Короче говоря, он используется для построенияListsby'consing' головной элемент и хвостовой список. Это как класс который представляет собой список минусов и который может быть использован в качестве экстрактора, но чаще всего это метод on список. Как указывает Пабло Фернандес, поскольку он заканчивается двоеточием, это право ассоциативный, что означает, что получатель вызова метода находится справа, а аргумент-слева от оператора. Таким образом, вы можете элегантно выразить консинг как перед новый головной элемент в существующий список:val x = 2 :: 3 :: Nil // same result as List(2, 3) val y = 1 :: x // yields List(1, 2, 3)это эквивалентно
val x = Nil.::(3).::(2) // successively prepend 3 and 2 to an empty list val y = x.::(1) // then prepend 1использование в качестве объекта экстрактора выглядит следующим образом:
def extract(l: List[Int]) = l match { case Nil => "empty" case head :: Nil => "exactly one element (" + head + ")" case head :: tail => "more than one element" } extract(Nil) // yields "empty" extract(List(1)) // yields "exactly one element (33)" extract(List(2, 3)) // yields "more than one element"это выглядит как оператор здесь, но это действительно просто еще один (более читаемый) способ пишу
def extract2(l: List[Int]) = l match { case Nil => "empty" case ::(head, Nil) => "exactly one element (" + head + ")" case ::(head, tail) => "more than one element" }вы можете прочитать больше о экстракторах в этот пост.
Я считаю, что современная IDE имеет решающее значение для понимания крупных проектов scala. Поскольку эти операторы также являются методами, в intellij idea я просто control-click или control-b В определения.
вы можете управлять-щелкните правой кнопкой мыши в оператор минусов (::) и в конечном итоге в scala javadoc говоря "добавляет элемент в начале этого списка."В определяемые пользователем операторы, это становится еще более важным, поскольку они могут быть определены в трудно найти неявные преобразования... интерфейс IDE знает где неявное было определено.
Scala наследует большую часть арифметические операторы Java. Это включает в себя побитовое или
|(один символ), побитовое и&, побитовое исключающее-ИЛИ^, а также логические (булевы) или||(два символа трубы) и логический-и&&. Интересно, что вы можете использовать односимвольные операторы наboolean, так что Ява иш логических операторов являются абсолютно лишними:true && true // valid true & true // valid as well 3 & 4 // bitwise-and (011 & 100 yields 000) 3 && 4 // not validкак указано в другом сообщении, вызовы заканчиваются равными знак
=, решаются (если метод с таким именем не существует!) путем переназначения:var x = 3 x += 1 // `+=` is not a method in `int`, Scala makes it `x = x + 1`эта "двойная проверка" позволяет легко обменять изменяемую коллекцию на неизменяемую:
val m = collection.mutable.Set("Hallo") // `m` a val, but holds mutable coll var i = collection.immutable.Set("Hallo") // `i` is a var, but holds immutable coll m += "Welt" // destructive call m.+=("Welt") i += "Welt" // re-assignment i = i + "Welt" (creates a new immutable Set)
просто добавляя к другим отличным ответам. Scala предлагает два часто критикуемых символьных оператора,
/:(foldLeft) и:\(foldRight) операторы, первый из которых является правоассоциативным. Таким образом, следующие три утверждения эквивалентны:( 1 to 100 ).foldLeft( 0, _+_ ) ( 1 to 100 )./:( 0 )( _+_ ) ( 0 /: ( 1 to 100 ) )( _+_ )как и эти три:
( 1 to 100 ).foldRight( 0, _+_ ) ( 1 to 100 ).:\( 0 )( _+_ ) ( ( 1 to 100 ) :\ 0 )( _+_ )
Comments