Scala语法有很多符号。由于使用搜索引擎很难找到这些类型的名字,所以一个全面的列表将会很有帮助。
Scala中所有的符号都是什么,每个符号都有什么作用?
特别地,我想知道 ->, ||=, ++=, <=, _._,::,和:+=。
Scala语法有很多符号。由于使用搜索引擎很难找到这些类型的名字,所以一个全面的列表将会很有帮助。
Scala中所有的符号都是什么,每个符号都有什么作用?
特别地,我想知道 ->, ||=, ++=, <=, _._,::,和:+=。
当前回答
Scala和其他语言的一个(在我看来是好的)区别是,它允许你用几乎任何字符来命名你的方法。
您列举的不是“标点符号”,而是简单明了的方法,因此它们的行为因对象而异(尽管存在一些约定)。
例如,查看Scaladoc文档中的List,您将看到这里提到的一些方法。
请记住以下几点:
大多数情况下,A操作符+= B组合转换为A = A操作符B,如||=或++=示例。 以:结尾的方法是右结合的,这意味着A:: B实际上是B.::(A)。
您可以通过浏览Scala文档找到大部分答案。在这里保留一个参考将重复工作,并且它将很快落后:)
其他回答
你可以先根据某些标准对它们进行分组。在这篇文章中,我将只解释下划线字符和右箭头。
_._ 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 symbol in Scala. There are several posts about it, for example this blog entry all 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 _._1 or something similar, that is, invoking method _._1 on the function argument. _1 to _22 are the methods of tuples which extract a particular element of a tuple. Example:
val tup = ("Hallo", 33)
tup._1 // extracts "Hallo"
tup._2 // extracts 33
现在让我们假设函数应用程序快捷方式的用例。给定一个将整数映射到字符串的映射:
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 implicit conversions in object scala.Predef in scope. The conversion which takes place here is
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的map方法将key和value的元组传递给函数参数。由于我们只对值(字符串)感兴趣,所以我们使用元组上的_2方法提取它们。
为了便于教学,我将运算符分为四类:
关键字/保留符号 自动导入的方法 常用的方法 语法糖/成分
幸运的是,大多数类别都体现在这个问题中:
-> // 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
大多数这些方法的确切含义取决于定义它们的类。例如,<=在Int上表示“小于或等于”。第一个,->,我将在下面给出一个例子。::可能是定义在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
不过我可能忘了别的意思。
自动导入的方法
因此,如果您在上面的列表中没有找到要查找的符号,那么它一定是一个方法,或者是一个方法的一部分。但是,通常情况下,你会看到一些符号和类的文档没有那个方法。当发生这种情况时,要么您正在查看一个或多个方法与其他方法的组合,要么该方法已导入到作用域,要么通过导入的隐式转换可用。
这些仍然可以在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
在上面的例子中,->是在ArrowAssoc类中通过方法any2ArrowAssoc定义的,该方法接受类型为A的对象,其中A是同一方法的无界类型参数。
常用的方法
因此,许多符号只是类上的方法。例如,如果你有
List(1, 2) ++ List(3, 4)
你会在ScalaDoc for List中找到方法++。但是,在搜索方法时必须注意一个约定。以冒号(:)结尾的方法绑定到右边而不是左边。换句话说,上面的方法调用相当于:
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.
这里有很好的详尽的答案。
对我来说,关键的一点是,这有两类
op提到的符号是scala sdk中的函数名。在scala中,使用这些字符(包括unicode字符)来编写函数名是合法的。这将是一个很长的列表,试图从sdk中提到所有已经在其他答案中提到的问题
还有一些符号不是函数名,而是语言语法本身的一部分,如=>,_或操作符,如&&,||等。
<=就像你会“读”它:'小于或等于'。所以它是一个数学运算符,在<(小于?)、>(大于?)、==(等于?)、!=(不等于?)、<=(小于或等于?)和>=(大于或等于?)的列表中。
这不能与=>混淆,后者是一种右向双箭头,用于将参数列表与函数体分离,并将模式匹配中的测试条件(case块)与匹配发生时执行的函数体分离。你可以在我之前的两个回答中看到这样的例子。一、函数使用:
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"
}
Scala和其他语言的一个(在我看来是好的)区别是,它允许你用几乎任何字符来命名你的方法。
您列举的不是“标点符号”,而是简单明了的方法,因此它们的行为因对象而异(尽管存在一些约定)。
例如,查看Scaladoc文档中的List,您将看到这里提到的一些方法。
请记住以下几点:
大多数情况下,A操作符+= B组合转换为A = A操作符B,如||=或++=示例。 以:结尾的方法是右结合的,这意味着A:: B实际上是B.::(A)。
您可以通过浏览Scala文档找到大部分答案。在这里保留一个参考将重复工作,并且它将很快落后:)