關於scala搞出的新概念的語法糖

對於scala搞那麼多語法糖和新概念真是又愛又恨。愛的是scala引入了java一直沒有的lambda特性,這對於使用高階函數抽象來處理集合數據很是有愛(spark簡潔的RDD處理得益於此)。恨的是scala搞那麼多的新概念和語法糖。java

下面就來講說這些個語法糖和新概念:編程

1、單例對象(singleton object)
scala沒有static關鍵字,搞出了個object關鍵字來新建單例對象。在單例對象中的成員都是static的。因此要寫util類通常都要用這個東西。函數

object xxUtil {
   def process(xx:String):String = {
     xx
   }
}

2、伴生對象和伴生類(companion object & companion class)、獨立對象(standalone object)
這兩個概念是相互的。假設有object A 和 class A 兩個同名了。這時候就能夠說:object A是class A的「伴生對象」;class A是object A的「伴生類」。當一個object B沒有同名的class B的時候,object B就叫「作獨立對象」。
伴生帶來的特權就是:它們能夠互相訪問私有成員。
class和object的區別:
  一、單例對象不能用new來初始化。
  二、單例對象不能帶參數。
  三、單例對象在第一次調用的時候才初始化。

3、略坑的函數調用語法糖
一、神奇的點號省略。
雖然有的時候帶來必定方便,不過組合lambda特性等東西,代碼簡直就能亮瞎你的氪金狗眼。spa

//無參數
"hello" toUpperCase
"hello".toUpperCase
"hello".toUpperCase()
//一個參數
"hello".indexOf "h"
"hello" indexOf "h"
//多個參數
"hello world" substring (0, 3)
//所有搞在一塊兒
 "hello world" substring (0, 3)  toUpperCase() indexOf "h"
//配合上匿名函數
Array(1,2,3) map ((i:Int)=> i+1)
 1 to 3 map ((i:Int)=> i+1)

二、神奇的forscala

//這個for挺正常的吧?
for(i <- 1 to 4) println(i)
//這個呢!
 for(i <- 1 to 4 if i > 1) println(i)
//這個呢!!!
 for(i <- 1 to 4 if i > 1; if i < 4; if i % 2 ==0) println(i)

三、神奇的花括號{}代替小括號()語法
聽說,若是函數調用只傳入一個參數,花括號能夠代替小括號(最後一個括號也能夠替換),scala粑粑不會打你屁股。設計

println("hello")
println{"hello"}

def xx(i:Int)(j:Int) = i+j
 xx(1){2} //result: 3
(xx(1)_){3} //curry化調用
(xx(1)_)(3) //curry化調用,不信你不懵

//看了上面的還沒懵?那就再來個
def xx(i:Int)(j:(Int)=>Int) = j(i)
xx(1){i=> i+10}

//有愛的一面
//假設我定義一個hbase的scan方法
def scan(tableName:String, cf:String, startRow:String, stopRow:String) (processFn:(Result) => Unit) = {
  //...
}
//那麼我能夠這麼天然的調用  
scan(t1, cf, startRow, stopRow) { r =>  
   //TODO process result  
}

四、神奇的byName函數和調用
爲了讓本身定義的方法看起來和scala內建語法同樣「和諧」,搞出了一個byName參數和byName函數。code

//抄襲scala編程的例子
def myAssert(pred:()=>Boolean) = if(!pred()) throw new AssertionError
myAssert(()=> 5<3) //()=> 5<3匿名函數看起來是否是不爽?

//由於()=> 5<3 的調用看起來不天然。因此要將()這部分去掉。
def myAssert2(pred: => Boolean) = if(!pred) throw new AssertionError
myAssert2(5<3) // 這樣看起來爽多了。

4、類型的上下界
對象

class foo[T <% A]{...} //弱上界<%。關係較弱:T可以隱式轉換爲Ordered[T]
class foo[T <: A]{...} //上界<:。T必須是A的子類,A是T的類型上界。
class foo[T >: A]{...} //下界>:。T必須是A的父類,A是T類型的下界。

5、協變和逆變
+T: 協變:class Queue[+T] {}。若是C<:A,則Queue[C] <: Queue[A]
-T: 逆變 : class Queue[-T] {}。若是C<:A,則Queue[C] >: Queue[A]

6、隱式轉換
隱式轉換,是對應於顯式的轉換來講的。好比有"1234".toInt,這就是顯式的轉換,不直接調用toInt方法轉換的就是隱式轉換。ci

implicit def str2Int(s:String):Int = Integer.parseInt(s) //隱式str轉int
def add(a:Int, b:Int) = a+b
add("1",2) //先把"1"隱式轉換爲1,再加起來。

7、case類 (轉載者注:模板類,就是爲模式匹配設計的)
case類是什麼,case類就是一個class,但是能用來作模式匹配。因此搞出這麼個東西。。。
case類和通常類的不一樣點:
一、會有和類名同樣的工廠方法。不須要使用new來建立這個類對象。string

case class Var(name:String)
val v1 = Var("peter") //和類名同樣的工廠方法

二、case類的參數列表默認是val的。
三、自動添加了toString,hashCode和equals的天然實現。

case類的最大的用途就是用來作模式匹配。

case class Var(name:String)
val v1 = Var("peter")
v1 match {
   case Var(name) => name
   case _ =>
}
//匹配出name爲peter

8、模式守衛
模式守衛(pattern guard)接pattern以後,開始與if。只有模式守衛返回true纔算成功。

10 match {
  case n:Int if 1< n => println(n) //if到=>以前,這段爲模式守衛
  case _ =>
}
相關文章
相關標籤/搜索