Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1575282
  • 博文数量: 399
  • 博客积分: 8508
  • 博客等级: 中将
  • 技术积分: 5302
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-14 09:28
个人简介

能力强的人善于解决问题,有智慧的人善于绕过问题。 区别很微妙,小心谨慎做后者。

文章分类

全部博文(399)

文章存档

2018年(3)

2017年(1)

2016年(1)

2015年(69)

2013年(14)

2012年(17)

2011年(12)

2010年(189)

2009年(93)

分类: 架构设计与优化

2015-05-02 09:07:34

Scala 是构建在 JVM 上的静态类型的脚本语言,而脚本语言总是会有些约定来增强灵活性。灵活性可以让掌握了它的人如鱼得水,也会让初学者不知所措。比如说 Scala 为配合 DSL 在方法调用时有这么一条约定:

1) 在明确了方法调用的接收者的情况下,若方法只有一个参数时,调用的时候就可以省略点及括号。如 “0 to 2”,实际完整调用是 “0.to(2)”。但 “println(2)” 不能写成 “println 10“”,因为未写出方法调用的接收者 Console,所以可以写成 “Console println 10”.

2) 用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对 apply 方法的调用; balance(x,y)  =>   balance.apply(x,y)

3) 与此相似的,当对带有括号并包括一到若干参数的进行赋值时,编译器将使用对象的 update 方法对“括号里的参数和等号右边的值”执行调用。   balance() = x   => balance.update(x)

4) 函数定义简式

def f() { return .. }

调用:f, f()皆可

始终返回:Unit

def f() = ...

调用:f, f()皆可

返回Unit或者值

def f = ...

调用:f

返回Unit或者值



5) 偏函数 用下划线代替1+个参数的函数叫偏函数(partially applied function)

val p0 = sum _ // 正确

val p1 = sum(10,_,20) // 错误

val p2 = sum(10,_:Int,20) // 正确

val p3 = sum(_:Int,100,_:Int)

p0(1,2,3) // 6

p2(100) // 130

p3(10,1) // 111

或者:

  (sum _)(1 2 3) // 6

  (sum(1,_:Int,3))(2) // 6

  (sum(_:Int,2,_:Int))(1,3) // 6

从上面可以看出,partial函数是一个正常函数中抽出来的一部分(参数不全),故称为partial函数。

6) 匿名参数

((i:Int, j:Int) => i+j)(3, 4) // 7 可以写成 ((_:Int) + (_:Int))(3,4) // 7    注意:括号(_:Int)括号是必须的

参数_在最后则可以省略,例如
1 to 5 map (10*) 1 to 5 foreach println


7) Curry化

例如:

def sum(a:Int, b:Int) = { a + b } // sum(1, 2) = 3

Curry化后:

def sum(a:Int)(b:Int) = { a + b } // sum(1)(2) = 3

或者:

def sum(a:Int) = { (b:Int)=> a + b } // sum(1)(2) = 3

// 调用方式二:val t1 = sum(10);  val t2 = t1(20)


8) Iterator不属于集合类型,只是逐个存取集合中元素的方法,一次性的消费

使用while
val it = Iterator(1,3,5,7) 或者 val it = List(1,3,5,7).iterator
while(it.hasNext) println(it.next)

使用for
for(e<- Iterator(1,3,5,7)) println(e)

使用foreach
Iterator(1,3,5,7) foreach println

 
Iterator也可以使用map的方法:

Iterator(1,3,5,7) map (10*) toList // List(10, 30, 50, 70)

Iterator(1,3,5,7) dropWhile (5>) toList // List(5,7)

9) 尾递归
定义:函数尾(最后一条语句)是递归调用的函数。

tail-recursive会被优化成循环,所以没有堆栈溢出的问题。

 

线性递归的阶乘:

def nn1(n:Int):BigInt = if (n==0) 1 else nn1(n-1)*n

println(nn1(1000)) // 4023...000

println(nn1(10000)) // 崩溃:(


尾递归的阶乘:

def nn2(n:Int, rt:BigInt):BigInt = if (n==0) rt else nn2(n-1, rt*n)

println(nn2(1000,1)) // 40...8896

println(nn2(10000,1)) // 2846...000

10) Parallel Collection
(1 to 10).par foreach println

11)  协变和逆变(co-|contra-)variance

概念
使用“+”“-”差异标记

 

trait Queue[T] {}   =>  非变

trait Queue[+T] {}  =>  协变

如果S extends A (S为子类型,A为父类型),

则Queue[S]为子类型,Queue[A]为父类型

S <: A => Queue[S] <: Queue[A]      
      

trait Queue[-T] {} =>  逆变

如果S extends A (S为子类型,A为父类型)

则Queue[S]为父类型,Queue[A]为子类型,和协变互逆

S <: A => Queue[S] >: Queue[A]

-A是A的子集,叫逆变

+B是B的超集,叫协变


类型上下界

<%

foo[T <% Ordered[T]](...)

关系较弱:T能够隐式转换为Ordered[T]

<:

foo[T <: Ordered[T]](...)

关系较强:T必须是Ordered[T]的子类型,即T的类型范围小于Ordered[T],Ordered[T]为上界

>:

foo[T >: A](...)

关系较强:T必须是A的父类型,即Tde类型范围大于A,A为下界
 

协变、逆变结合上下界

例子1:

trait c1[+T] {

def m[K >: T](x:K) = x }


trait c1[-T] {

def m[K <: T](x:K) = x }


object c2 extends c1[Int]

c2.m(3) // 3

c2.m(3.0) // 3.0

c2.m("abc") // “abc"


object c2 extends c1[Int]

c2.m(3) // 3

c2.m(3.0) // 报错

c2.m("abc") // 报错

 

 

 

例子2:

// 非变

case class T1[T](e:T)

val v1:T1[java.lang.Integer] = new T1(100)

val v2:T1[java.lang.Integer] = v1

v2.e // 100

val v3:T1[java.lang.Number] = v1 // 报错

 

// 协变

case class T1[+T](e:T)

val v1:T1[java.lang.Integer] = new T1(100)

val v2:T1[java.lang.Integer] = v1

v2.e // 100

val v3:T1[java.lang.Number] = v1 // 合法

v3.e // 100

val v4:T1[java.lang.Integer] = v3 //非法

 

// 逆变

class T1[-T](e:T)

val v1:T1[java.lang.Number] = new T1(100)

val v2:T1[java.lang.Number] = v1

val v3:T1[java.lang.Integer] = v1 // 合法

val v4:T1[java.lang.Number] = v3 // 非法
阅读(866) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~