scala语法糖

Posted 写轮眼之大数据

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala语法糖相关的知识,希望对你有一定的参考价值。

人再怎么苦里熬,

不应当忘记谦和与傲骨。

—— 简媜

对于scala搞那么多语法糖和新概念真是又爱又恨。爱的是scala引入了java一直没有的lambda特性,这对于使用高阶函数抽象来处理集合数据非常有爱(spark简洁的RDD处理得益于此)。恨的是scala搞那么多的新概念和语法糖。

一、单例对象(singleton object)
      scala没有static关键字,搞出了个object关键字来新建单例对象。在单例对象中的成员都是static的。所以要写util类一般都要用这个东西。

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

单例对象用于持有一个类的唯一实例。通常用于工厂模式。

object Timer { var count = 0
def currentCount(): Long = { count += 1 count }}
可以这样使用:scala> Timer.currentCount()res0: Long = 1

单例对象可以和类具有相同的名称,此时该对象也被称为“伴生对象”。我们通常将伴生对象作为工厂使用。

下面是一个简单的例子,可以不需要使用’new’来创建一个实例了。

class Bar(foo: String)
object Bar { def apply(foo: String) = new Bar(foo)}
二、伴生对象和伴生类(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的区别:
  1、单例对象不能用new来初始化。
  2、单例对象不能带参数。
  3、单例对象在第一次调用的时候才初始化。

三、略坑的函数调用语法糖
1、神奇的点号省略。
虽然有的时候带来一定方便,不过组合lambda特性等东西,代码简直就能亮瞎你的氪金狗眼。

//无参数
"hello" toUpperCase
"hello".toUpperCase
"hello".toUpperCase()
//一个参数
"hello".indexOf "h"
"hello" indexOf "h"
//多个参数
"hello world" substring (03)
//全部搞在一起
 "hello world" substring (03)  toUpperCase() indexOf "h"
//配合上匿名函数
Array(1,2,3) map ((i:Int)=> i+1)
 1 to 3 map ((i:Int)=> i+1)

2、神奇的for

//这个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)

3、神奇的花括号{}代替小括号()语法
据说,如果函数调用只传入一个参数,花括号可以代替小括号(最后一个括号也可以替换),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  
}

4、神奇的byName函数和调用
为了让自己定义的方法看起来和scala内建语法一样“和谐”,搞出了一个byName参数和byName函数。

//抄袭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// 这样看起来爽多了。

四、类型的上下界

class foo[T <% A]{...} //弱上界<%。关系较弱:T能够隐式转换为Ordered[T]
class foo[T <: A]{...} //上界<:。T必须是A的子类,AT的类型上界。
class foo[T >: A]{...} //下界>:。T必须是A的父类,AT类型的下界。

五、协变和逆变
+T: 协变:class Queue[+T] {}。如果C<:A,则Queue[C] <: Queue[A]
-T: 逆变 : class Queue[-T] {}。如果C<:A,则Queue[C] >: Queue[A]

六、隐式转换
隐式转换,是对应于显式的转换来说的。比如有"1234".toInt,这就是显式的转换,不直接调用toInt方法转换的就是隐式转换。

implicit def str2Int(s:String):Int = Integer.parseInt(s) //隐式str转int
def add(a:Int, b:Int) = a+b
add("1",2//先把"1"隐式转换为1,再加起来。

七、case类 (注:模板类,就是为模式匹配设计的)
case类是什么,case类就是一个class,可是能用来做模式匹配。所以搞出这么个东西。。。
case类和一般类的不同点:
1、会有和类名一样的工厂方法。不需要使用new来创建这个类对象。

case class Var(name:String)
val v1 = Var("peter"//和类名一样的工厂方法

2、case类的参数列表默认是val的。
3、自动添加了toString,hashCode和equals的自然实现。

case类的最大的用途就是用来做模式匹配。

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

样本类就是被设计用在模式匹配中的。让我们简化之前的计算器分类器的例子。

val hp20b = Calculator("HP", "20B")val hp30b = Calculator("HP", "30B")
def calcType(calc: Calculator) = calc match { case Calculator("HP", "20B") => "financial" case Calculator("HP", "48G") => "scientific" case Calculator("HP", "30B") => "business" case Calculator(ourBrand, ourModel) => "Calculator: %s %s is of unknown type".format(ourBrand, ourModel)}
最后一句也可以这样写 case Calculator(_, _) => "Calculator of unknown type"
或者我们完全可以不将匹配对象指定为Calculator类型 case _ => "Calculator of unknown type"
或者我们也可以将匹配的值重新命名。 case c@Calculator(_, _) => "Calculator: %s of unknown type".format(c)

八、模式守卫
模式守卫(pattern guard)接pattern之后,开始与if。只有模式守卫返回true才算成功。

10 match {
  case n:Int if 1n => println(n) //if到=>之前,这段为模式守卫
  case _ =>
}

九、异常

Scala中的异常可以在try-catch-finally语法中通过模式匹配使用。

try { remoteCalculatorService.add(1, 2)} catch { case e: ServerIsDownException => log.error(e, "the remote calculator service is unavailable. should have kept your trusty HP.")} finally { remoteCalculatorService.close()}
try也是面向表达式的val result: Int = try { remoteCalculatorService.add(1, 2)} catch { case e: ServerIsDownException => { log.error(e, "the remote calculator service is unavailable. should have kept your trusty HP.") 0 }} finally { remoteCalculatorService.close()}





获取更多资料: