Scala的所有符号运算符是什么意思?
Scala语法有很多符号。 由于使用search引擎很难find这些名称,因此综合列表将会有所帮助。
Scala中的所有符号是什么,每个符号又是什么?
特别是,我想知道->
, ||=
, ++=
, <=
, _._
, ::
和:+=
。
为了教学目的我把操作员分成四类 :
- 关键字/保留的符号
- 自动导入的方法
- 常用的方法
- 句法糖/组合物
那么幸运的是,大多数类别都是在这个问题中performance出来的:
-> // 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
大多数这些方法的确切含义取决于正在定义它们的类。 例如, <=
on Int
表示“小于或等于” 。 第一个, ->
,我会举例如下。 ::
可能是在List
定义的方法(尽pipe它可能是同名的对象),并且:+=
可能是在不同的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
这些都是语言的一部分 ,因此,可以在正确描述语言的任何文本中find,例如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
不过,我可能忘了其他一些意思。
自动导入的方法
所以,如果你在上面的列表中没有find你想要的符号,那么它必须是一个方法,或者是一个方法的一部分。 但是,通常你会看到一些符号,而这个类的文档就没有这个方法。 发生这种情况时,要么使用其他方法查看一个或多个方法的组合,要么已经将该方法导入到作用域中,或者通过导入的隐式转换可用。
这些仍然可以在ScalaDoc上find :你只需知道在哪里寻找它们。 或者,如果没有,请查看索引 (目前在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
的方法,它接收作为参数的正在接收方法的types的对象。 例如:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
在上面的例子中, ->
是通过ArrowAssoc
方法在类ArrowAssoc
定义的,该方法接受A
types的对象,其中A
是同一方法的无界types参数。
常用的方法
所以,很多符号只是一个类的方法。 例如,如果你这样做
List(1, 2) ++ List(3, 4)
您将在ScalaDoc for List上find方法++
。 但是,search方法时必须注意一个约定。 以冒号(:)结尾的方法绑定到右侧而不是左侧。 换句话说,上面的方法调用相当于:
List(1, 2).++(List(3, 4))
如果我有,而不是1 :: List(2, 3)
,这将相当于:
List(2, 3).::(1)
所以在查找以冒号结尾的方法时,需要查看右侧的types。 考虑一下,例如:
1 +: List(2, 3) :+ 4
第一种方法( +:
:)绑定到右边,并在List
上find。 第二种方法( :+
)只是一个普通的方法,并绑定到左侧 – 再次,在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.
斯卡拉和其他语言之间的一个(良好的,海事组织)差异是它可以让你用几乎任何angular色来命名你的方法。
你列举的不是“标点符号”,而是简单明了的方法,因此它们的行为在一个对象之间是不同的(尽pipe有一些约定)。
例如,查看List的Scaladoc文档 ,你会看到你在这里提到的一些方法。
有些事情要记住:
-
大多数情况下,
A operator+equal B
组合转换为A = A operator B
,就像在||=
或++=
示例中一样。 -
以
B.::(A)
结尾的方法是正确的关联,这意味着A :: B
实际上是B.::(A)
。
您将通过浏览Scala文档find大多数答案。 在这里保持一个参考将重复努力,它会很快落后:)
你可以根据一些标准将它们分组。 在这篇文章中,我只是解释下划线字符和右箭头。
_._
包含句点。 Scala中的一段时间总是表示一个方法调用 。 所以你有接收器的时间的左边,和右边的消息(方法名称)。 现在_
是Scala中的一个特殊符号 。 有几个关于它的post,比如这个博客的所有用例。 这是一个匿名函数捷径 ,它是一个函数的快捷方式,它接受一个参数并调用方法_
。 现在_
不是一个有效的方法,所以当然你会看到_._1
或类似的东西,也就是调用函数参数的方法_._1
。 _1
到_22
是提取元组的特定元素的元组方法。 例:
val tup = ("Hallo", 33) tup._1 // extracts "Hallo" tup._2 // extracts 33
现在让我们假设一个用例函数的应用程序快捷方式。 给定一个将整数映射到string的映射:
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
具有创buildTuple2
的->
方法。 因此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的元组传递给函数参数。 由于我们只对值(string)感兴趣,所以我们用元组中的_2
方法提取它们。
作为Daniel和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") }
<=
就像你“读”它:“小于或等于”。 所以它是一个math运算符,在<
(小于?), >
(大于?), ==
(等于?), !=
(不等于?), <=
(小于等于?), >=
(大于或等于?)。
这不能与=>
混淆 ,这是一种双右箭头 ,用于将参数列表从函数主体中分离出来,并将模式匹配中的testing条件( case
block)与正文发生匹配。 你可以在我以前的两个答案中看到这个例子。 一,function用途:
coll.map(tup => tup._2.reverse)
这已经缩写为省略了这些types。 跟随function将是
// 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" }
关于::
有另一个覆盖::
case的Stackoverflow条目。 简而言之,它被用来构造一个由“ 包含 ”一个头元素和一个尾列表构成的列表。 它既是一个代表cons'ed list的类 ,也可以用作提取器,但最常见的是列表中的一个方法 。 正如Pablo Fernandez所指出的那样,由于它以冒号结尾,所以它是正确的联想 ,这意味着方法调用的接收者在右边,而在运算符左边的是参数。 通过这种方式,您可以优雅地将重要元素表示为将新元素添加到现有列表中:
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的思想中,我只是将control-click或control-b引入到定义中。
你可以右键点击一个cons运算符(::),最后在scala javadoc上说:“在这个列表的开头添加一个元素”。 在用户定义的运算符中,这变得更加关键,因为它们可以被定义在难以find的含义中……您的IDE知道隐式被定义的位置。
Scalainheritance了大部分Java的算术运算符 。 这包括按位或|
(单pipe道字符),按位和&
,按位排他或^
,以及逻辑(布尔)或||
(两个pipe道字符)和逻辑和&&
。 有趣的是,你可以在boolean
上使用单字符运算符,所以java'ish逻辑运算符是完全冗余的:
true && true // valid true & true // valid as well 3 & 4 // bitwise-and (011 & 100 yields 000) 3 && 4 // not valid
正如在另一篇文章中指出的那样,通过重新分配来parsing以等号=
结尾的呼叫(如果具有该名称的方法不存在!):
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)
只需添加到其他优秀的答案。 斯卡拉还有右:关联中缀运算符/:
foldLeft
)和:\
( foldRight
)运算符。 所以下面三个陈述是一样的:
( 1 to 100 ).foldLeft( 0, _+_ ) ( 1 to 100 )./:( 0 )( _+_ ) ( 0 /: ( 1 to 100 ) )( _+_ )
foldRight和:\
。