您的位置:首页 > 大数据 > 人工智能

Scala的main方法、包、for循环、操作符重载、 系统定义、implicit隐式转换及泛型

2014-10-16 11:50 696 查看

22.13.
main方法

Scala的main方法(包括所有类似java的static方法)必须定义在一个object内:

object Test1 {

def main(args: Array[String]) {

println("hello world")

}

}

2.13.1. Application

不带命令行参数的简化main方法:

object app1 extends Application {

println("hello world")

}

2.14. package, import

2.14.1. import

Scala的import可以只在局部作用域内生效;

可以格式 “import javax.swing.{JFrame=>jf}”来声明类型的别名。

jf.show()

l import javax.swing._

l import java.util.{List, Map}

l import java.util._, java.io._

Scala 缺省导入如下包:

l java.lang.*

l scala.*

l scala.Predef

由于Scala的package可以是相对路径下定义,有可能命名冲突,可以用:

import _root_.java.lang.Long

2.14.2. package

package com.wr3 {

// import java.nio._ // "*" 是scala的正常函数名,所以用_

class c1 {

def m1() { println("c1.m1()") }

}

object o1 {

def main(args: Array[String]) {

println("o1.main()")

new c1().m1()

}

}

}

编译:

fsc package.scala

运行:

java com.wr3.o1 // 方式1

scala com.wr3.o1 // 方式2

2.14.3. 包对象

Scala2.8+支持包对象(package object),除了和2.8之前一样可以有下级的object和class,还可以直接有下级变量和函数,例如:

-------------------------------- foo.scala

package p0

package object p1 {

val a = 10

def b = "hello " + a

def main(args:Array[String]):Unit = printf("%s", p0.p1.b)

}

--------------------------------

p1就是一个包对象,a和b就是包p1直属的常量和函数,

$fsc foo.scala 命令产生如下class:

./p0/p1/package.class

调用:

scala p0.p1.package

2.15. if..else

没有java的:

b = (x>y) ? 100 : -1

就用:

if (x>y) 100 else -1

2.16. 循环操作

map

m->m

flatMap

m->n

indices

m->m

foreach

m->Unit

for (... if ...) yield

m->n

collect { case ... if ... => ... }

m->n

filter, filterNot

m->n

take

m->n

takeWhile

m->n

forall

m->1 (true|false)

reduceLeft, foldLeft

m->1

scanLeft

m->m+1

exists

m->1 (true|false)

find

m->1 (或者None)

count

m->1

span, partition

m->2

2.16.1. for

循环中的变量不用定义,如:

for(i<-1 to 10; j=i*i) println(j)

for (s <- ss) foo(s)

for (i <- 0 to n) foo(i) // 包含n,即Range(0,1,2,...,n,n+1)

for (i <- 0 until n) foo(i) // 不包含n,即Range(0,1,2,3,...,n)

例如:

for (n<-List(1,2,3,4) if n%2==1) yield n*n // List(1, 9)

等价于不用for的写法:

List(1,2,3,4).filter(_%2==1).map(n => n*n)

for (n<-Array(1,2,3,4) if n%2==1) yield n*n // Array(1, 9)

注意:如果if后面不止一条语句,要用{..}包裹。

var s = 0; for (i <- 0 until 100) { s += i } // s = 4950

for条件语句即可用(),也可用{}

如果条件是多行,不能用(),要用{}

for(i<-0 to 5; j<-0 to 2) yield i+j

// Vector(0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5 , 6, 5, 6, 7)

for{i<-0 to 5

j<-0 to 2} yield i+j

例子1:

// 边长21以内所有符合勾股弦的三角形:

def triangle(n: Int) = for { x <- 1 to 21 y <- x to 21 z <- y to 21 if x * x + y * y == z * z } yield (x, y, z)

结果:

// Vector((3,4,5), (5,12,13), (6,8,10), (8,15,17), (9,12,15), (12,16,20))

2.16.1. for .. yield

把每次循环的结果“移”进一个集合(类型和循环内的一致)

for {子句} yield {循环体}

正确:

for (e<-List(1,2,3)) yield (e*e) // List(1,4,9)

for {e<-List(1,2,3)} yield { e*e } // List(1,4,9)

for {e<-List(1,2,3)} yield e*e // List(1,4,9)

错误:

for (e<-List(1,2,3)) { yield e*e } // 语法错误,yield不能在任何括号内

2.16.2. foreach

List(1,2,3).foreach(println)

1

2

3

也可以写成:

(1 to 3).foreach(println)

或者

(1 until 4) foreach println

或者

Range(1,3) foreach println

注意:

l to包含,until不包含(最后的数)

l 都可以写步长,如:

1 to (11,2) // 1,3,5,7,9,11 步长为2

== 1 to 11 by 2

1 until (11,2) // 1,3,5,7,9

== 1 until 11 by 2

val r = (1 to 10 by 4) // (1,5,9), r.start=r.first=1; r.end=10, r.last=9

l 也可以是BigInt

(1:BigInt) to 3

2.16.3. forall

"所有都符合"——相当于 A1 && A2 && A3 && ... && Ai && ... && An

(1 to 3) forall (0<) // true

(-1 to 3) forall (0<) // false

又如:

def isPrime(n:Int) = 2 until n forall (n%_!=0)

for (i<-1 to 100 if isPrime(i)) println(i)

(2 to 20) partition (isPrime _) // (2,3,5,7,11,13,17,19), (4,6,8,9,10,12,14,15,16,18,20)

也可直接调用BigInt的内部方法:

(2 to 20) partition (BigInt(_) isProbablePrime(10))

// 注:isProbablePrime(c)中c越大,是质数的概率越高,10对应概率:1 - 1/(2**10) = 0.999

2.16.4. reduceLeft

reduceLeft 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,等等,直至整个列表。例如

计算阶乘:

def fac(n: Int) = 1 to n reduceLeft(_*_)

fac(5) // 5*4*3*2 = 120

相当于:

((((1*2)*3)*4)*5)

计算sum:

List(2,4,6).reduceLeft(_+_) // 12

相当于:

((2+4)+6)

取max:

List(1,4,9,6,7).reduceLeft( (x,y)=> if (x>y) x else y ) // 9

或者简化为:

List(1,4,9,6,7).reduceLeft(_ max _) // 9

相当于:

((((1 max 4) max 9) max 6) max 7)

2.16.5. foldLeft scanLeft

累加或累乘

def sum(L: List[Int]): Int = {

var result = 0

for (item <- L)

result += item

result

}

更scalable的写法:

def sum(L: Seq[Int]) = L.foldLeft(0)((a, b) => a + b)

def sum(L: Seq[Int]) = L.foldLeft(0)(_ + _)

def sum(L: List[Int]) = (0/:L){_ + _}//暂时还不理解的请看2.16.6的注释

调用:

sum(List(1,3,5,7)) // 16

乘法:

def multiply(L: Seq[Int]) = L.foldLeft(1)(_ * _)

multiply(Seq(1,2,3,4,5)) // 120

multiply(1 until 5+1) // 120

2.16.6. scanLeft

List(1,2,3,4,5).scanLeft(0)(_+_) // (0,1,3,6,10,15)

相当于:

(0,(0+1),(0+1+2),(0+1+2+3),(0+1+2+3+4),(0+1+2+3+4+5))

List(1,2,3,4,5).scanLeft(1)(_*_) // (1,2,6,24,120)

相当于

(1, 1*1, 1*1*2, 1*1*2*3, 1*1*2*3*4, 1*1*2*3*4*5)

注:

l (z /: List(a, b, c))(op) 相当于 op(op(op(z, a), b), c)

简单来说:加法用0,乘法用1

l (List(a, b, c) :\ z) (op) equals op(a, op(b, op(c, z)))

/:和:\的用法

2.16.7. take drop splitAt

1 to 10 by 2 take 3 // Range(1, 3, 5)

1 to 10 by 2 drop 3 // Range(7, 9)

1 to 10 by 2 splitAt 2 // (Range(1, 3),Range(5, 7, 9))

例子:前10个质数

def prime(n:Int) = (! ((2 to math.sqrt(n).toInt) exists (i=> n%i==0)))

2 to 100 filter prime take 10

2.16.8. takeWhile, dropWhile, span

while语句的缩写,

takeWhile (...)

等价于:while (...) { take }

dropWhile (...)

等价于:while (...) { drop }

span (...)

等价于:while (...) { take; drop }

1 to 10 takeWhile (_<5) // (1,2,3,4)

1 to 10 takeWhile (_>5) // () //Takes longestprefixof elements that satisfy a predicate.

10 to (1,-1) takeWhile(_>6) // (10,9,8,7)

1 to 10 takeWhile (n=>n*n<25) // (1, 2, 3, 4)

如果不想直接用集合元素做条件,可以定义var变量来判断:

例如,从1 to 10取前几个数字,要求累加不超过30:

var sum=0;

val rt = (1 to 10).takeWhile(e=> {sum=sum+e;sum<30}) // Range(1, 2, 3, 4, 5, 6, 7)

注意:takeWhile中的函数要返回Boolean,sum<30要放在最后;

1 to 10 dropWhile (_<5) // (5,6,7,8,9,10)

1 to 10 dropWhile (n=>n*n<25) // (5,6,7,8,9,10)

1 to 10 span (_<5) // ((1,2,3,4),(5,6,7,8)

List(1,0,1,0) span (_>0) // ((1), (0,1,0))

注意,partition是和span完全不同的操作

List(1,0,1,0) partition (_>0) // ((1,1),(0,0))

2.16.9. break、continue

Scala中没有break和continue语法!需要break得加辅助boolean变量,或者用库(continue没有).

例子1:打印'a' to 'z'的前10个

var i=0; val rt = for(e<-('a' to 'z') if {i=i+1;i<=10}) printf("%d:%s\n",i,e)

或者:

('a' to 'z').slice(0,10).foreach(println)

例子2:1 to 100 和小于1000的数

var (n,sum)=(0,0); for(i<-0 to 100 if (sum+i<1000)) { n=i; sum+=i }

// n = 44, sum = 990

例子3:使用库来实现break

import scala.util.control.Breaks._

for(e<-1 to 10) { val e2 = e*e; if (e2>10) break; println(e) }

2.17. 操作符重载

注意:其实Scala没有操作符,更谈不上操作符重载;+-/*都是方法名,如1+2其实是(1).+(2)

object operator {

class complex(val i:Int, val j:Int) { // val 是必须的

def + (c2: complex) = {

new complex (i+c2.i, j+c2.j)

}

override def toString() = { "(" + i + "," + j + ")" }

}

def main(args:Array[String]) = {

val c1 = new complex(3, 10)

val c2 = new complex(5, 70)

printf("%s + %s = %s", c1, c2, c1+c2)

}

}

编译:fsc operator.scala

运行:java operator // (3,10) + (5,70) = (8,80)

2.18. 系统定义scala._

scala._自动加载,只有发生类名冲突时才需要带上scala.包名。

scala.AnyValue

所有基本类型的根

Int,Char,Boolean,Double,Unit

scala.AnyRef

所有引用类型的根

相当于java的java.lang.Object

scala.Null

所有引用类型的子类

scala.Nothing

所有全部类型的子类

scala.List

不可变的List

scala特色的不可变List

scala.Int

scala中可以用int作为别名

Double,Float等类似

2.19. implicit隐式转换

用途:

l 把一种object类型安全地自动转换成另一种object类型;

l 不改动已有class设计即可添加新的方法;

2.19.1. 类型转换 (用法一)

implicit def foo(s:String):Int = Integer.parseInt(s) // 需要时把String->Int

def add(a:Int, b:Int) = a+b

add("100",8) // 108, 先把"100"隐式转换为100

2.19.2. 例子:阶乘n!

第一步:写函数

def factorial(n: Int) = 1 to n reduceLeft(_*_)

第二步:定义 "!" 函数

class m1(n: Int) {

def ! = factorial(n)

}

implicit def m2(n:Int) = new m1(n) // 隐式转换,即在需要时把n转换为new m1(n)

注意:上面可以用匿名类简化为:

implicit def m2(n:Int) = new { def ! = factorial(n) }

第三步:使用

val n = 100

printf("%d! = %s\n", n, (n!)) // n! 相当于 new m1(n).!()

println(10!)

2.19.3. 例子:cout //Converting the receiver

import java.io._

class C1(p:PrintStream) {

def << (a:Any) = {

p.print(a)

p.flush

p

}

}

implicit def anyFuncName(p:PrintStream) = new C1(p)

val endl = '\n'

System.out<<"hello"<<" world"<<endl

System.out has no '<<' function, implicitly convert it as C1 object and call the function '<<'

2.19.4. 例子:定义?:

implicit def elvisOperator[T](alt: T) = new {

def ?:[A >: T](pred: A) = if (pred == null) alt else pred

}

null ?: "" // ""

"abc" ?: "" // "abc"

10 ?: 0 // 10

(null ?: 0).asInstanceOf[Int] // 0

2.19.5. 已有Object加新方法(用法二 Converting the receiver)

object NewMethod {

// 定义新方法join()

implicit def foo1[T](list: List[T]) = new {

def join(s:String) = list.mkString(s)

}

// 测试

def main(args : Array[String]) : Unit = {

Console println List(1,2,3,4,5).join(" - ") // " 1 - 2 - 3 - 4 – 5"

}

}

解释:

编译器发现List没有join(String)方法,就发查找代码中有没有定义在implicit def xx(List)内的 join(String)方法,如果有就调用这个。

为Int增加乘方操作:

def pow(n:Int, m:Int):Int = if (m==0) 1 else n*pow(n,m-1)

implicit def foo(n:Int) = new {

def **(m:Int) = pow(n,m)

}

2**10 // 1024

例子2:定义如ruby的10.next

implicit def foo(n:Int) = new { def next = n+1 }

10.next // 11

2.20. type做alias

相当于C语言的类型定义typedef,建立新的数据类型名(别名);在一个函数中用到同名类时可以起不同的别名

例如:

type JDate = java.util.Date

type SDate = java.sql.Date

val d1 = new JDate() // 相当于 val d = new java.util.Date()

val d2 = new SDate() // 相当于 val d = new java.sql.Date()

注意:type也可以做泛型

用法三 Implicit parameters,缺省参数

class PreferredPrompt(val preference: String)

object Greeter {

def greet(name: String)(implicit prompt: PreferredPrompt) {

println("Welcome, "+ name +". The system is ready.")

println(prompt.preference)

}

}

implicit val prompt = new PreferredPrompt("Yes, master> ")

scala> Greeter.greet("Joe")

Welcome, Joe. The system is ready.

Yes, master>

2.21. 泛型

2.21.1. 函数中的泛型:

def foo[T](a:T) = println("value is " + a)

foo(10) // "value is 10"

foo(3.14) // "value is 3.14"

foo("hello") // "value is hello"

2.21.2. 类中的泛型:

class C1[T] {

private var v:T = _ // 初始值为T类型的缺省值

def set(v1:T) = { v = v1 }

def get = v

}

new C1[Int].set(10).get // 10

new C1[String].set("hello").get // "hello"

2.21.3. 泛型定义type

abstract class C1 {

type T

val e:T

}

abstract class C2 {

type T

val list:List[T]

def len = list.length

}

def m1(e1:Int) = new C1 {

type T = Int

val e = e1

}

def m2(e1:List[Int]) = new C2 {

type T = Int

val list = e1

}

Console println m1(10) // 10

Console println m2(List(1,2,3,4,5)).len // 5

注意:type也可以做数据类型的alias,类似C语言中的typedef

2.22. 枚举Enum

Scala没有在语言层面定义Enumeration,而是在库中实现:

例子1:

object Color extends Enumeration {

type Color = Value

val RED, GREEN, BLUE, WHITE, BLACK = Value

}

注:有点费解,特别是Enumeration defines an inner class named Value

Color.RED // Color.Value = RED

import Color._

val colorful = Color.values filterNot (e=> e==WHITE || e==BLACK)

colorful foreach println // RED\nGREEN\nBLUE

例子2:

object Color extends Enumeration {

val RED = Value("红色")

val GREEN = Value("绿色")

val BLUE = Value("蓝色")

val WHITE = Value("黑")

val BLASK = Value("白")

}

Color.RED // Color.Value = 红色

import Color._

val colorful = Color.values filterNot (List("黑","白") contains _.toString)

colorful foreach println //红色\n绿色\n蓝色

22
2.13. main方法

Scala的main方法(包括所有类似java的static方法)必须定义在一个object内:

object Test1 {

def main(args: Array[String]) {

println("hello world")

}

}


2.13.1. Application

不带命令行参数的简化main方法:

object app1 extends Application {

println("hello world")

}


2.14. package,
import


2.14.1. import

Scala的import可以只在局部作用域内生效;

可以格式 “import javax.swing.{JFrame=>jf}”来声明类型的别名。

jf.show()

l import javax.swing._

l import java.util.{List, Map}

l import java.util._, java.io._

Scala 缺省导入如下包:

l java.lang.*

l scala.*

l scala.Predef

由于Scala的package可以是相对路径下定义,有可能命名冲突,可以用:

import _root_.java.lang.Long


2.14.2. package

package com.wr3 {

// import java.nio._ // "*" 是scala的正常函数名,所以用_

class c1 {

def m1() { println("c1.m1()") }

}

object o1 {

def main(args: Array[String]) {

println("o1.main()")

new c1().m1()

}

}

}

编译:

fsc package.scala

运行:

java com.wr3.o1 // 方式1

scala com.wr3.o1 // 方式2

2.14.3. 包对象

Scala2.8+支持包对象(package object),除了和2.8之前一样可以有下级的object和class,还可以直接有下级变量和函数,例如:

-------------------------------- foo.scala

package p0

package object p1 {

val a = 10

def b = "hello " + a

def main(args:Array[String]):Unit = printf("%s", p0.p1.b)

}

--------------------------------

p1就是一个包对象,a和b就是包p1直属的常量和函数,

$fsc foo.scala 命令产生如下class:

./p0/p1/package.class

调用:

scala p0.p1.package


2.15. if..else

没有java的:

b = (x>y) ? 100 : -1

就用:

if (x>y) 100 else -1


2.16. 循环操作

map

m->m

flatMap

m->n

indices

m->m

foreach

m->Unit

for (... if ...) yield

m->n

collect { case ... if ... => ... }

m->n

filter, filterNot

m->n

take

m->n

takeWhile

m->n

forall

m->1 (true|false)

reduceLeft, foldLeft

m->1

scanLeft

m->m+1

exists

m->1 (true|false)

find

m->1 (或者None)

count

m->1

span, partition

m->2


2.16.1. for

循环中的变量不用定义,如:

for(i<-1 to 10; j=i*i) println(j)

for (s <- ss) foo(s)

for (i <- 0 to n) foo(i) // 包含n,即Range(0,1,2,...,n,n+1)

for (i <- 0 until n) foo(i) // 不包含n,即Range(0,1,2,3,...,n)

例如:

for (n<-List(1,2,3,4) if n%2==1) yield n*n // List(1, 9)

等价于不用for的写法:

List(1,2,3,4).filter(_%2==1).map(n => n*n)

for (n<-Array(1,2,3,4) if n%2==1) yield n*n // Array(1, 9)

注意:如果if后面不止一条语句,要用{..}包裹。

var s = 0; for (i <- 0 until 100) { s += i } // s = 4950

for条件语句即可用(),也可用{}

如果条件是多行,不能用(),要用{}

for(i<-0 to 5; j<-0 to 2) yield i+j

// Vector(0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5 , 6, 5, 6, 7)

for{i<-0 to 5

j<-0 to 2} yield i+j

例子1:

// 边长21以内所有符合勾股弦的三角形:
def triangle(n: Int) = for {   x <- 1 to 21   y <- x to 21   z <- y to 21   if x * x + y * y == z * z } yield (x, y, z)


结果:

// Vector((3,4,5), (5,12,13), (6,8,10), (8,15,17), (9,12,15), (12,16,20))


2.16.1. for
.. yield

把每次循环的结果“”进一个集合(类型和循环内的一致)

for {子句} yield {循环体}

正确:

for (e<-List(1,2,3)) yield (e*e) // List(1,4,9)

for {e<-List(1,2,3)} yield { e*e } // List(1,4,9)

for {e<-List(1,2,3)} yield e*e // List(1,4,9)

错误:

for (e<-List(1,2,3)) { yield e*e } // 语法错误,yield不能在任何括号内


2.16.2. foreach

List(1,2,3).foreach(println)

1

2

3

也可以写成:

(1 to 3).foreach(println)

或者

(1 until 4) foreach println

或者

Range(1,3) foreach println

注意:

l to包含,until不包含(最后的数)

l 都可以写步长,如:

1 to (11,2) // 1,3,5,7,9,11 步长为2

== 1 to 11 by 2

1 until (11,2) // 1,3,5,7,9

== 1 until 11 by 2

val r = (1 to 10 by 4) // (1,5,9), r.start=r.first=1; r.end=10, r.last=9

l 也可以是BigInt

(1:BigInt) to 3


2.16.3. forall

"所有都符合"——相当于 A1 && A2 && A3 && ... && Ai && ... && An

(1 to 3) forall (0<) // true

(-1 to 3) forall (0<) // false

又如:

def isPrime(n:Int) = 2 until n forall (n%_!=0)

for (i<-1 to 100 if isPrime(i)) println(i)

(2 to 20) partition (isPrime _) // (2,3,5,7,11,13,17,19), (4,6,8,9,10,12,14,15,16,18,20)

也可直接调用BigInt的内部方法:

(2 to 20) partition (BigInt(_) isProbablePrime(10))

// 注:isProbablePrime(c)中c越大,是质数的概率越高,10对应概率:1
- 1/(2**10) = 0.999


2.16.4. reduceLeft

reduceLeft 方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,等等,直至整个列表。例如

计算阶乘:

def fac(n: Int) = 1 to n reduceLeft(_*_)

fac(5) // 5*4*3*2 = 120

相当于:

((((1*2)*3)*4)*5)

计算sum:

List(2,4,6).reduceLeft(_+_) // 12

相当于:

((2+4)+6)

取max:

List(1,4,9,6,7).reduceLeft( (x,y)=> if (x>y) x else y ) // 9

或者简化为:

List(1,4,9,6,7).reduceLeft(_ max _)
// 9

相当于:

((((1 max 4) max 9) max 6) max 7)


2.16.5. foldLeft scanLeft

累加或累乘

def sum(L: List[Int]): Int = {

var result = 0

for (item <- L)

result += item

result

}

更scalable的写法:

def sum(L: Seq[Int]) = L.foldLeft(0)((a, b) => a + b)

def sum(L: Seq[Int]) = L.foldLeft(0)(_ + _)

def sum(L: List[Int]) = (0/:L){_ + _}//暂时还不理解的请看2.16.6的注释

调用:

sum(List(1,3,5,7)) // 16

乘法:

def multiply(L: Seq[Int]) = L.foldLeft(1)(_ * _)

multiply(Seq(1,2,3,4,5)) // 120

multiply(1 until 5+1) // 120


2.16.6. scanLeft

List(1,2,3,4,5).scanLeft(0)(_+_) // (0,1,3,6,10,15)

相当于:

(0,(0+1),(0+1+2),(0+1+2+3),(0+1+2+3+4),(0+1+2+3+4+5))

List(1,2,3,4,5).scanLeft(1)(_*_) // (1,2,6,24,120)

相当于

(1, 1*1, 1*1*2, 1*1*2*3, 1*1*2*3*4, 1*1*2*3*4*5)

注:

l (z /: List(a,
b, c))(op) 相当于 op(op(op(z, a), b), c)


简单来说:加法用0,乘法用1

l (List(a, b, c) :\ z)
(op) equals op(a, op(b, op(c, z)))

/:和:\的用法


2.16.7. take
drop splitAt

1 to 10 by 2 take 3 // Range(1, 3, 5)

1 to 10 by 2 drop 3 // Range(7, 9)

1 to 10 by 2 splitAt 2 // (Range(1, 3),Range(5, 7, 9))

例子:前10个质数

def prime(n:Int) = (! ((2 to math.sqrt(n).toInt) exists (i=> n%i==0)))

2 to 100 filter prime take 10


2.16.8. takeWhile,
dropWhile, span

while语句的缩写,
takeWhile (...)

等价于:while (...) { take }

dropWhile (...)

等价于:while (...) { drop }

span (...)

等价于:while (...) { take; drop }

1 to 10 takeWhile (_<5) // (1,2,3,4)

1 to 10 takeWhile (_>5) // () //Takes longestprefixof
elements that satisfy a predicate.

10 to (1,-1) takeWhile(_>6) // (10,9,8,7)

1 to 10 takeWhile (n=>n*n<25) // (1, 2, 3, 4)

如果不想直接用集合元素做条件,可以定义var变量来判断:

例如,从1 to 10取前几个数字,要求累加不超过30:

var sum=0;

val rt = (1 to 10).takeWhile(e=> {sum=sum+e;sum<30}) // Range(1, 2, 3, 4, 5, 6, 7)

注意:takeWhile中的函数要返回Boolean,sum<30要放在最后;

1 to 10 dropWhile (_<5) // (5,6,7,8,9,10)

1 to 10 dropWhile (n=>n*n<25) // (5,6,7,8,9,10)

1 to 10 span (_<5) // ((1,2,3,4),(5,6,7,8)

List(1,0,1,0) span (_>0) // ((1), (0,1,0))

注意,partition是和span完全不同的操作

List(1,0,1,0) partition (_>0) // ((1,1),(0,0))


2.16.9. break、continue

Scala中没有break和continue语法!需要break得加辅助boolean变量,或者用库(continue没有).

例子1:打印'a' to 'z'的前10个

var i=0; val rt = for(e<-('a' to 'z') if {i=i+1;i<=10})
printf("%d:%s\n",i,e)

或者:

('a' to 'z').slice(0,10).foreach(println)

例子2:1 to 100 和小于1000的数

var (n,sum)=(0,0); for(i<-0 to 100 if (sum+i<1000)) { n=i; sum+=i }

// n = 44, sum = 990

例子3:使用库来实现break

import scala.util.control.Breaks._

for(e<-1 to 10) { val e2 = e*e; if (e2>10) break; println(e) }


2.17. 操作符重载

注意:其实Scala没有操作符,更谈不上操作符重载;+-/*都是方法名,如1+2其实是(1).+(2)

object operator {

class complex(val i:Int, val j:Int) { // val 是必须的

def + (c2: complex) = {

new complex (i+c2.i, j+c2.j)

}

override def toString() = { "(" + i + "," + j + ")" }

}

def main(args:Array[String]) = {

val c1 = new complex(3, 10)

val c2 = new complex(5, 70)

printf("%s + %s = %s", c1, c2, c1+c2)

}

}

编译:fsc operator.scala

运行:java operator // (3,10) + (5,70) = (8,80)


2.18. 系统定义scala._

scala._自动加载,只有发生类名冲突时才需要带上scala.包名。
scala.AnyValue

所有基本类型的根

Int,Char,Boolean,Double,Unit

scala.AnyRef

所有引用类型的根

相当于java的java.lang.Object

scala.Null

所有引用类型的子类

scala.Nothing

所有全部类型的子类

scala.List

不可变的List

scala特色的不可变List

scala.Int

scala中可以用int作为别名

Double,Float等类似


2.19. implicit隐式转换

用途:

l 把一种object类型安全地自动转换成另一种object类型;

l 不改动已有class设计即可添加新的方法;


2.19.1. 类型转换
(用法一)

implicit def foo(s:String):Int = Integer.parseInt(s) // 需要时把String->Int

def add(a:Int, b:Int) = a+b

add("100",8) // 108, 先把"100"隐式转换为100


2.19.2. 例子:阶乘n!

第一步:写函数

def factorial(n: Int) = 1 to n reduceLeft(_*_)

第二步:定义 "!" 函数

class m1(n: Int) {

def ! = factorial(n)

}

implicit def m2(n:Int) = new m1(n) // 隐式转换,即在需要时把n转换为new
m1(n)

注意:上面可以用匿名类简化为:

implicit def m2(n:Int) = new { def ! = factorial(n) }

第三步:使用

val n = 100

printf("%d! = %s\n", n, (n!)) // n! 相当于 new m1(n).!()

println(10!)


2.19.3. 例子:cout
//
Converting the receiver

import java.io._

class C1(p:PrintStream) {

def << (a:Any) = {

p.print(a)

p.flush

p

}

}

implicit def anyFuncName(p:PrintStream) = new C1(p)

val endl = '\n'

System.out<<"hello"<<" world"<<endl

System.out has no '<<' function, implicitly convert it as C1 object and call the function '<<'


2.19.4. 例子:定义?:

implicit def elvisOperator[T](alt: T) = new {

def ?:[A >: T](pred: A) = if (pred == null) alt else pred

}


null ?: "" // ""

"abc" ?: "" // "abc"

10 ?: 0 // 10

(null ?: 0).asInstanceOf[Int] // 0


2.19.5. 已有Object加新方法(用法二 Converting
the receiver
)

object NewMethod {

// 定义新方法join()

implicit def foo1[T](list: List[T])
= new {

def join(s:String)
= list.mkString(s)

}

// 测试

def main(args : Array[String])
: Unit = {

Console println List(1,2,3,4,5).join("
- ") // " 1 - 2 - 3 - 4 – 5"

}

}

解释:

编译器发现List没有join(String)方法,就发查找代码中有没有定义在implicit
def xx(List)内的 join(String)方法,如果有就调用这个。

为Int增加乘方操作:

def pow(n:Int, m:Int):Int = if (m==0) 1 else n*pow(n,m-1)

implicit def foo(n:Int) = new {

def **(m:Int) = pow(n,m)

}

2**10 // 1024

例子2:定义如ruby的10.next

implicit def foo(n:Int) = new { def next = n+1 }

10.next // 11


2.20. type做alias

相当于C语言的类型定义typedef,建立新的数据类型名(别名);在一个函数中用到同名类时可以起不同的别名

例如:

type JDate = java.util.Date

type SDate = java.sql.Date

val d1 = new JDate() // 相当于 val d = new java.util.Date()

val d2 = new SDate() // 相当于 val d = new java.sql.Date()

注意:type也可以做泛型

用法三 Implicit parameters,缺省参数

class PreferredPrompt(val preference: String)

object Greeter {

def greet(name: String)(implicit prompt: PreferredPrompt) {

println("Welcome, "+ name +". The system is ready.")

println(prompt.preference)

}

}

implicit val prompt = new PreferredPrompt("Yes, master> ")

scala> Greeter.greet("Joe")

Welcome, Joe. The system is ready.

Yes, master>


2.21. 泛型


2.21.1. 函数中的泛型:

def foo[T](a:T) = println("value is " + a)

foo(10) // "value is 10"

foo(3.14) // "value is 3.14"

foo("hello") // "value is hello"


2.21.2. 类中的泛型:

class C1[T] {

private var v:T = _ // 初始值为T类型的缺省值

def set(v1:T) = { v = v1 }

def get = v

}

new C1[Int].set(10).get // 10

new C1[String].set("hello").get // "hello"


2.21.3. 泛型定义type

abstract class C1 {

type T

val e:T

}

abstract class C2 {

type T

val list:List[T]

def len = list.length

}

def m1(e1:Int) = new C1 {

type T = Int

val e = e1

}

def m2(e1:List[Int]) = new C2 {

type T = Int

val list = e1

}

Console println m1(10) // 10

Console println m2(List(1,2,3,4,5)).len // 5

注意:type也可以做数据类型的alias,类似C语言中的typedef


2.22. 枚举Enum

Scala没有在语言层面定义Enumeration,而是在库中实现:

例子1:

object Color extends Enumeration {

type Color = Value

val RED, GREEN, BLUE, WHITE, BLACK = Value

}
注:有点费解,特别是Enumeration defines an inner class named Value

Color.RED // Color.Value = RED

import Color._

val colorful = Color.values filterNot (e=> e==WHITE || e==BLACK)

colorful foreach println // RED\nGREEN\nBLUE

例子2:

object Color extends Enumeration {

val RED = Value("红色")

val GREEN = Value("绿色")

val BLUE = Value("蓝色")

val WHITE = Value("黑")

val BLASK = Value("白")

}

Color.RED // Color.Value = 红色

import Color._

val colorful = Color.values filterNot (List("黑","白") contains _.toString)

colorful foreach println //红色\n绿色\n蓝色
2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: