實際上Scala沒有操作符, 只是以操作符的格式使用方法.
操作符的優先級取決於第一個字符(除了賦值操作符), 而結合性取決於最后一個字符
Scala的操作符命名更加靈活:)
操作符
中置操作符(Infix)
a 操作符 b
上述操作符
代表一個帶有兩個參數的方法(一個隱式參數和一個顯示參數)
1 to 10 即 1.to(10) Range
1 -> 10 即 1.->(10) 對偶操作符(1, 10)
在自己的類中定義操作符很簡單, 以你自己想要做操作符的標識符來定義一個方法就好了.
class MyOperator(factor1: Int) {
def &@(factor2: Int) = {
new MyOperator(factor2 * factor1)
}
override def toString: String = " " + factor1
}
object TestMyOp extends App {
val multi = new MyOperator(4)
println(multi.&@(2))
}
/*output
8
*/
一元操作符
后置操作符: 操作符出現在參數之后
a 操作符
1 toString 即 1.toString()
前置操作符: 出現在參數之前
+, -, !, ~ 可以作為前置操作符, 它們被轉化為名為 unary_ 的操作符的方法調用
如 -a
, 即 a.unary_-
賦值操作符
形式為
a 操作符= b 即, a = a 操作符 b
如 a += b 即: a = a + b
技術細節注意一下:
- <=, >=, != 不是賦值操作符
- 以
=
開頭的操作符不是賦值操作符(==, ===, =/=等) - 如果a有一個名為
操作符=
的方法, 那么該方法會被直接調用, 而不是執行賦值操作
操作符優先級
由於Scala可以任意定義操作符, 他需要一套優先級判定方案;
對所有的操作符生效, 同時保留人們熟悉的標准操作符的優先順序
除了賦值操作符之外, 優先級由操作符的首字符
決定, 比方說操作符以*
開頭優先級高於+
開頭的;
以下是操作符的首字符的優先級, 從上到下, 優先級依次降低
首字符優先級 |
---|
* / % |
+ - |
: |
< > |
! = |
& |
^ |
| |
非以上操作符 |
- 最低優先級的操作符為賦值操作符
- 出現在同一行的字符所產生的操作符有優先級相同, 比如說 + 和 -> 有着相同的優先級
- 后置操作符的優先級低於中置操作符
操作符結合性
當有一系列的相同優先級的操作符時,操作符的結合性決定了它們從左到右求值還是從右到左求值.
在Scala中操作符都是左結合的, 除了:
- 以冒號
:
結尾的操作符 - 賦值操作符
右結合的二元操作符是第二個參數的函數
2 :: Nil 即 Nil.::(2)
apply, update方法
f(arg1, arg2, ...)
如果f
不是一個函數或者方法, 那么這個表達式等同於調用apply方法, 除非它出現在賦值語句的左側, 即 f(arg1, arg2, ...) = value
, 則調用的是update方法
f.apply(arg1, arg2, ...)
f.update(arg1, arg2, ..., value)
這機制被用於數組和映射, apply方法常用於伴生對象中, 用來構造對象而不用顯式的使用 new
關鍵字
val happy = new scala.collection.mutable.HashMap[String, Int]
happy("smile") = 10 // happy.update("smile", 10)
happy("smile") // happy.apply("smile")
提取器
所謂提取器就是一個帶有 unapply
方法的對象, 你可以把unapply 方法當成伴生對象中 apply
方法的反向應用, apply 方法接受構造參數, 然后將他們變成對象; 而unapply接受一個對象, 然后從中提取值---這些值就是當時用來構造對象的值.
每個樣例類都自動具備apply和unapply方法
通常而言, 模式匹配可能會失敗, 因此采用 Option 類型作為 unapply
返回值
object Name extends App{
val me = "wang bin"
val Name(first, last) = me
println(first + " " + last)
println(first)
def unapply(input: String): Option[(String, String)] = {
val pos = input.indexOf(" ")
if (pos == -1) None
else Some((input.substring(0, pos), input.substring(pos + 1)))
}
}
帶單個參數或者無參數的構造器
在 Scala 中沒有只有一個元素的元組, 如果 unapply 要提取單值, 則它應該返回一個目標類型的 Option[A], 比如下面的 Option[Int]
object Number extends App {
val Number(digit) = "1111 "
println(digit)
def unapply(input: String): Option[Int] = {
try {
Some(Integer.parseInt(input.trim))
} catch {
case ex: NumberFormatException => None
}
}
}
提取器也可以只是測試其輸入而不將值提取出來, 這樣的話, unapply
方法應該返回 Boolean
. 例如:
object IsCompound extends App{
println(NameRes("wang bin"))
println(NameRes("tom hanks ming"))
def unapply(arg: String):Boolean = arg.contains(" ")
def NameRes(name: String) = name match {
// @ IsCompound() ()不能丟 測試的是 last 是否包含空格
case Name(first, last @ IsCompound()) => first
case Name(first, last ) => last
}
}
/*output
bin
tom
*/
unapplySeq 方法
要提取任意長度
的值的序列, 我們應該用 unapplySeq 來命名我們的方法, 它返回值為 Option[Seq[A]], 其中 A 是被提取值的類型. 舉例來說 Name 提取器可以產出名字中所有組成部分的序列, 這樣一來就可以提取任意數量的變量了
object Name extends App{
val name = "tom li hi"
println(NameSeq("happy smile")) // 輸出: happly
println(NameSeq("tom hanks ming toylor")) // 輸出 ming
def NameSeq(name: String) = name match {
// @ IsCompound() ()不能丟 測試的是 last 是否包含空格
case Name(first, last) => first
case Name(first, "good", last ) => last
case Name(first, nd, rd, _*) => rd
case _ => "NameSeq"
}
def unapplySeq(input: String): Option[Seq[String]] = {
if (input.trim == "") None else Some(input.split("\\s+"))
}
}