Scala 操作符與提取器


實際上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+"))
        }
}




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM