Scala 的所有符号运算符是什么意思?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7888944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What do all of Scala's symbolic operators mean?
提问by 0__
Scala syntax has a lot of symbols. Since these kinds of names are difficult to find using search engines, a comprehensive list of them would be helpful.
Scala 语法有很多符号。由于使用搜索引擎很难找到这些类型的名称,因此它们的完整列表会有所帮助。
What are all of the symbols in Scala, and what does each of them do?
Scala 中的所有符号是什么,每个符号的作用是什么?
In particular, I'd like to know about ->, ||=, ++=, <=, _._, ::, and :+=.
我特别想了解->, ||=, ++=, <=, _._, ::, 和:+=。
回答by Daniel C. Sobral
I divide the operators, for the purpose of teaching, into four categories:
为了教学的目的,我将算子分为四类:
- Keywords/reserved symbols
- Automatically imported methods
- Common methods
- Syntactic sugars/composition
- 关键字/保留符号
- 自动导入的方法
- 常用方法
- 语法糖/组成
It is fortunate, then, that most categories are represented in the question:
幸运的是,大多数类别都在问题中表示:
-> // 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
The exact meaning of most of these methods depend on the class that is defining them. For example, <=on Intmeans "less than or equal to". The first one, ->, I'll give as example below. ::is probably the method defined on List(though it couldbe the object of the same name), and :+=is probably the method defined on various Bufferclasses.
大多数这些方法的确切含义取决于定义它们的类。例如,<=on 的Int意思是“小于或等于”。第一个,->我将在下面给出示例。::可能是定义在上的方法List(尽管它可能是同名的对象),:+=也可能是在各种Buffer类上定义的方法。
So, let's see them.
那么,让我们看看他们。
Keywords/reserved symbols
关键字/保留符号
There are some symbols in Scala that are special. Two of them are considered proper keywords, while others are just "reserved". They are:
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
These are all part of the language, and, as such, can be found in any text that properly describe the language, such as Scala Specification(PDF) itself.
这些都是语言的一部分,因此,可以在任何正确描述语言的文本中找到,例如Scala 规范(PDF) 本身。
The last one, the underscore, deserve a special description, because it is so widely used, and has so many different meanings. Here's a sample:
最后一个,下划线,值得特别说明,因为它被广泛使用,并且有很多不同的含义。这是一个示例:
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
I probably forgot some other meaning, though.
不过,我可能忘记了一些其他含义。
Automatically imported methods
自动导入的方法
So, if you did not find the symbol you are looking for in the list above, then it must be a method, or part of one. But, often, you'll see some symbol and the documentation for the class will not have that method. When this happens, either you are looking at a composition of one or more methods with something else, or the method has been imported into scope, or is available through an imported implicit conversion.
因此,如果您在上面的列表中没有找到您要查找的符号,那么它一定是一个方法,或者是方法的一部分。但是,通常,您会看到一些符号,而该类的文档没有该方法。发生这种情况时,要么您正在查看一个或多个方法与其他方法的组合,要么该方法已导入到作用域中,或者可通过导入的隐式转换使用。
These can still be foundon ScalaDoc: you just have to know where to look for them. Or, failing that, look at the index(presently broken on 2.9.1, but available on nightly).
这些仍然可以在ScalaDoc上找到:您只需要知道在哪里可以找到它们。或者,如果失败,请查看索引(目前在 2.9.1 上已损坏,但每晚可用)。
Every Scala code has three automatic imports:
每个 Scala 代码都有三个自动导入:
// Not necessarily in this order
import _root_.java.lang._ // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._
The first two only make classes and singleton objects available. The third one contains all implicit conversions and imported methods, since Predefis an object itself.
前两个只使类和单例对象可用。第三个包含所有隐式转换和导入的方法,因为它Predef是一个对象本身。
Looking inside Predefquickly show some symbols:
Predef快速查看内部显示一些符号:
class <:<
class =:=
object <%<
object =:=
Any other symbol will be made available through an implicit conversion. Just look at the methods tagged with implicitthat receive, as parameter, an object of type that is receiving the method. For example:
任何其他符号都将通过隐式转换提供。只需查看标记为implicit接收方法的方法,作为参数,接收方法的类型对象。例如:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
In the above case, ->is defined in the class ArrowAssocthrough the method any2ArrowAssocthat takes an object of type A, where Ais an unbounded type parameter to the same method.
在上面的例子中,->是ArrowAssoc通过方法在类中定义的,该方法any2ArrowAssoc接受一个类型为 的对象A,其中A是同一方法的无界类型参数。
Common methods
常用方法
So, many symbols are simply methods on a class. For instance, if you do
因此,许多符号只是类上的方法。例如,如果你这样做
List(1, 2) ++ List(3, 4)
You'll find the method ++right on the ScalaDoc for List. However, there's one convention that you must be aware when searching for methods. Methods ending in colon (:) bind to the rightinstead of the left. In other words, while the above method call is equivalent to:
您可以在++ScalaDoc 上找到List 的方法。但是,在搜索方法时必须注意一个约定。以冒号 ( :)结尾的方法绑定到右侧而不是左侧。换句话说,虽然上面的方法调用等价于:
List(1, 2).++(List(3, 4))
If I had, instead 1 :: List(2, 3), that would be equivalent to:
相反1 :: List(2, 3),如果我有,那将相当于:
List(2, 3).::(1)
So you need to look at the type found on the rightwhen looking for methods ending in colon. Consider, for instance:
因此,在查找以冒号结尾的方法时,您需要查看右侧找到的类型。考虑,例如:
1 +: List(2, 3) :+ 4
The first method (+:) binds to the right, and is found on List. The second method (:+) is just a normal method, and binds to the left -- again, on List.
第一个方法 ( +:) 绑定到右侧,并在 上找到List。第二种方法 ( :+) 只是一个普通方法,并且绑定到左边——同样,在 上List。
Syntactic sugars/composition
语法糖/组成
So, here's a few syntactic sugars that may hide a method:
所以,这里有一些可能隐藏方法的语法糖:
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
The last one is interesting, because anysymbolic method can be combined to form an assignment-like method that way.
最后一个很有趣,因为任何符号方法都可以通过这种方式组合形成类似于赋值的方法。
And, of course, there's various combinations that can appear in code:
而且,当然,代码中可以出现各种组合:
(_+_) // 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.
回答by Pablo Fernandez
One (good, IMO) difference between Scala and other languages is that it lets you name your methods with almost any character.
Scala 和其他语言之间的一个(好的,IMO)区别在于它允许您使用几乎任何字符命名您的方法。
What you enumerate is not "punctuation" but plain and simple methods, and as such their behavior vary from one object to the other (though there are some conventions).
您列举的不是“标点符号”,而是简单明了的方法,因此它们的行为因一个对象而异(尽管有一些约定)。
For example, check the Scaladoc documentation for List, and you'll see some of the methods you mentioned here.
例如,查看List的Scaladoc 文档,您将看到这里提到的一些方法。
Some things to keep in mind:
要记住的一些事情:
Most of the times the
A operator+equal Bcombination translates toA = A operator B, like in the||=or++=examples.Methods that end in
:are right associative, this means thatA :: Bis actuallyB.::(A).
大多数情况下,
A operator+equal B组合转换为A = A operator B,就像在||=或++=示例中一样。以 结尾的方法
:是右结合的,这意味着A :: B实际上是B.::(A)。
You'll find most answers by browsing the Scala documentation. Keeping a reference here would duplicate efforts, and it would fall behind quickly :)
您可以通过浏览 Scala 文档找到大多数答案。在这里保留参考文献会重复工作,而且很快就会落后:)
回答by 0__
You can group those first according to some criteria. In this post I will just explain the underscore character and the right-arrow.
您可以根据某些标准首先将它们分组。在这篇文章中,我将只解释下划线字符和右箭头。
_._contains a period. A period in Scala always indicates a method call. So left of the period you have the receiver, and right of it the message (method name). Now _is a special symbolin Scala. There are several posts about it, for example this blog entryall use cases. Here it is an anonymous function short cut, that is it a shortcut for a function that takes one argument and invokes the method _on it. Now _is not a valid method, so most certainly you were seeing _._1or something similar, that is, invoking method _._1on the function argument. _1to _22are the methods of tuples which extract a particular element of a tuple. Example:
_._包含一个句号。Scala 中的句点始终表示方法调用。所以左边是接收者,右边是消息(方法名称)。Now_是Scala 中的一个特殊符号。有几篇关于它的文章,例如这个博客条目所有用例。这是一个匿名函数快捷方式,即它是一个函数的快捷方式,该函数接受一个参数并调用其_上的方法。Now_不是一个有效的方法,所以你肯定看到了_._1或类似的东西,即_._1在函数参数上调用方法。_1to_22是提取元组特定元素的元组方法。例子:
val tup = ("Hallo", 33)
tup._1 // extracts "Hallo"
tup._2 // extracts 33
Now lets assume a use case for the function application shortcut. Given a map which maps integers to strings:
现在让我们假设函数应用程序快捷方式的用例。给定一个将整数映射到字符串的映射:
val coll = Map(1 -> "Eins", 2 -> "Zwei", 3 -> "Drei")
Wooop, there is already another occurrence of a strange punctuation. The hyphen and greater-than characters, which resemble a right-hand arrow, is an operator which produces a Tuple2. So there is no difference in the outcome of writing either (1, "Eins")or 1 -> "Eins", only that the latter is easier to read, especially in a list of tuples like the map example. The ->is no magic, it is, like a few other operators, available because you have all implicitconversions in object scala.Predefin scope. The conversion which takes place here is
呜呜,又出现了一个奇怪的标点符号。连字符和大于号字符,类似于右手箭头,是一个产生Tuple2. 所以写(1, "Eins")or的结果没有区别1 -> "Eins",只是后者更容易阅读,尤其是在像 map 示例这样的元组列表中。这->不是魔术,它像其他一些运算符一样可用,因为您在范围内的object中有所有隐式转换scala.Predef。这里发生的转换是
implicit def any2ArrowAssoc [A] (x: A): ArrowAssoc[A]
Where ArrowAssochas the ->method which creates the Tuple2. Thus 1 -> "Eins"is actual the call Predef.any2ArrowAssoc(1).->("Eins"). Ok. Now back to the original question with the underscore character:
哪里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)
The underscore here shortens the following equivalent code:
此处的下划线缩短了以下等效代码:
coll.map(tup => tup._2.reverse)
Note that the mapmethod of a Map passes in the tuple of key and value to the function argument. Since we are only interested in the values (the strings), we extract them with the _2method on the tuple.
请注意,mapMap的方法将键和值的元组传递给函数参数。由于我们只对值(字符串)感兴趣,因此我们使用_2元组上的方法提取它们。
回答by om-nom-nom
As an addition to brilliant answers of Daniel and 0__, I have to say that Scala understands Unicodeanalogs for some of the symbols, so instead of
作为 Daniel 和 0__ 的精彩回答的补充,我不得不说 Scala 理解某些符号的Unicode类似物,因此而不是
for (n <- 1 to 10) n % 2 match {
case 0 => println("even")
case 1 => println("odd")
}
one may write
一个人可以写
for (n ← 1 to 10) n % 2 match {
case 0 ? println("even")
case 1 ? println("odd")
}
回答by 0__
Regarding ::there is another Stackoverflowentry which covers the ::case. In short, it is used to construct Listsby 'consing' a head element and a tail list. It is both a classwhich represents a cons'ed list and which can be used as an extractor, but most commonly it is a method ona list. As Pablo Fernandez points out, since it ends in a colon, it is right associative, meaning the receiver of the method call is to the right, and the argument to the left of the operator. That way you can elegantly express the consing as prependinga new head element to an existing list:
关于::有另一个Stackoverflow条目涵盖了这种::情况。简而言之,它用于Lists通过' consing'构造一个头元素和一个尾列表。它既是一个表示 cons 列表的类,也可以用作提取器,但最常见的是它是一个列表上的方法。正如 Pablo Fernandez 指出的那样,因为它以冒号结尾,所以它是右结合的,这意味着方法调用的接收者在右边,参数在运算符的左边。这样你就可以优雅地将 consing 表达为在现有列表中添加一个新的 head 元素:
val x = 2 :: 3 :: Nil // same result as List(2, 3)
val y = 1 :: x // yields List(1, 2, 3)
This is equivalent to
这相当于
val x = Nil.::(3).::(2) // successively prepend 3 and 2 to an empty list
val y = x.::(1) // then prepend 1
The use as extractor object is as follows:
作为提取器对象的使用如下:
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 (1)"
extract(List(2, 3)) // yields "more than one element"
This looks like an operator here, but it is really just another (more readable) way of writing
这在这里看起来像一个运算符,但它实际上只是另一种(更具可读性)的写作方式
def extract2(l: List[Int]) = l match {
case Nil => "empty"
case ::(head, Nil) => "exactly one element (" + head + ")"
case ::(head, tail) => "more than one element"
}
You can read more about extractors in this post.
回答by 0__
<=is just like you would "read" it: 'less than or equals'. So it's a mathematical operator, in the list of <(is less than?), >(is greater than?), ==(equals?), !=(is not equal?), <=(is less than or equal?), and >=(is greater than or equal?).
<=就像您会“阅读”它一样:“小于或等于”。所以它是一个数学运算符,在<(小于?),>(大于?),==(等于?),!=(不等于?),<=(小于或等于?),和>=(大于?或相等?)。
This must not be confusedwith =>which is kind of a double right-hand arrow, used to separate the argument list from the body of a function and to separate the testing condition in pattern matching (a caseblock) from the body executed when a match occurs. You can see example of this in my previous two answers. First, the function use:
这一定不能与which is kind of double right-hand arrow混淆,用于将参数列表与函数主体分开,并将模式匹配(块)中的测试条件与匹配发生时执行的主体分开. 你可以在我之前的两个答案中看到这样的例子。一、函数使用:=>case
coll.map(tup => tup._2.reverse)
which is already abbreviated as the types are omitted. The follow function would be
由于省略了类型,因此已被缩写。以下功能将是
// function arguments function body
(tup: Tuple2[Int, String]) => tup._2.reverse
and the pattern matching use:
和模式匹配使用:
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"
}
回答by nairbv
I consider a modern IDE to be critical for understanding large scala projects. Since these operators are also methods, in intellij idea I just control-click or control-b into the definitions.
我认为现代 IDE 对于理解大型 Scala 项目至关重要。由于这些运算符也是方法,因此在 Intellij 想法中,我只需在定义中按住 control-click 或 control-b 即可。
You can control-click right into a cons operator (::) and end up at the scala javadoc saying "Adds an element at the beginning of this list." In user-defined operators, this becomes even more critical, since they could be defined in hard-to-find implicits... your IDE knows where the implicit was defined.
您可以右键单击 cons 运算符 (::),然后在 Scala javadoc 中显示“在此列表的开头添加一个元素”。在用户定义的运算符中,这变得更加重要,因为它们可以在难以找到的隐式中定义……您的 IDE 知道隐式的定义位置。
回答by Mr MT
Just adding to the other excellent answers. Scala offers two often criticized symbolic operators, /:(foldLeft) and :\(foldRight) operators, the first being right-associative. So the following three statements are the equivalent:
只是添加到其他优秀的答案。Scala 提供了两个经常受到批评的符号运算符,/:( foldLeft) 和:\( foldRight) 运算符,第一个是右结合运算符。所以下面三个语句是等价的:
( 1 to 100 ).foldLeft( 0, _+_ )
( 1 to 100 )./:( 0 )( _+_ )
( 0 /: ( 1 to 100 ) )( _+_ )
As are these three:
就像这三个:
( 1 to 100 ).foldRight( 0, _+_ )
( 1 to 100 ).:\( 0 )( _+_ )
( ( 1 to 100 ) :\ 0 )( _+_ )
回答by 0__
Scala inherits most of Java's arithmetic operators. This includes bitwise-or |(single pipe character), bitwise-and &, bitwise-exclusive-or ^, as well as logical (boolean) or ||(two pipe characters) and logical-and &&. Interestingly, you can use the single character operators on boolean, so the java'ish logical operators are totally redundant:
Scala 继承了Java 的大部分算术运算符。这包括按位或|(单个管道字符)、按位与&、按位异或^,以及逻辑(布尔值)或||(两个管道字符)和逻辑与&&。有趣的是,您可以在 上使用单字符运算符boolean,因此 java'ish 逻辑运算符是完全多余的:
true && true // valid
true & true // valid as well
3 & 4 // bitwise-and (011 & 100 yields 000)
3 && 4 // not valid
As pointed out in another post, calls ending in an equals sign =, are resolved (if a method with that name does not exist!) by a reassignment:
正如在另一篇文章中指出的那样,以等号结尾的调用=通过重新分配来解决(如果具有该名称的方法不存在!):
var x = 3
x += 1 // `+=` is not a method in `int`, Scala makes it `x = x + 1`
This 'double-check' makes it possible, to easily exchange a mutable for an immutable collection:
这种“双重检查”可以轻松地将可变集合交换为不可变集合:
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)

