1. 关键字 trait
相当于 Java 中的接口,可以定义抽象方法,还可以定义字段和方法的实现,且一个类可以混合任意数量的 Trait。
1 2 3 4 5 6 7 8 trait Flyable { var maxHeight:Int def fly () def breathe () { println("呼吸..." ) } }
implicit
隐式转换函数是指在同一个作用域下面,一个给定输入类型并自动转换为指定返回类型的函数,这个函数和函数名、入参名均无关,只和入参类型以及返回类型有关
1.实战 display 只接受 String 类型的入参,否则编译会出错
1 def display (input:String ):Unit = println(input)
当想其能支持 Int 类型的入参时,除了我们重新定一个 def display(input:Int):Unit = println(input)
这样的函数以外,还可以在相同的作用域内用 implicit
关键字定义一个隐式转换函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ImplicitDemo { def display (input:String ):Unit = println(input) implicit def typeConvertor (input:Int ):String = input.toString implicit def typeConvertor (input:Boolean ):String = if (input) "true" else "false" def main (args: Array [String ]): Unit = { display("1212" ) display(12 ) display(true ) } }
2. 符号 1. ->
, <-
->
: 创建 map 时使用,表示映射
<-
: 左箭头在遍历时使用
1 2 3 4 5 6 7 8 9 val score = Map ("小明" -> 50 , "小红" -> 60 )val people = List ("小明" ,"小红" ,"小兰" )for (man <- people){ println(man) }
2. =>
可以看做是创建函数实例的语法糖。例如:A => T
,A,B => T
表示一个函数的输入参数类型是 A
,A,B
,返回值类型是 T
。() => T
表示函数输入参数为空,而 A => Unit
则表示函数没有返回值。
3. _
1. 匿名函数中参数 当匿名函数参数未被使用或只使用一次时,可用它来代替
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 scala> list.foreach(_ => println("Hello Scala" )) Hello Scala scala> val list = List (5 ,3 ,7 ,9 ,1 ) list: List [Int ] = List (5 , 3 , 7 , 9 , 1 ) scala> list.map(_ * 10 ) res0: List [Int ] = List (50 , 30 , 70 , 90 , 10 ) scala> list.sortWith(_ < _) res1: List [Int ] = List (1 , 3 , 5 , 7 , 9 )
2. 通配符 可用在泛型、模式匹配和导入语句中。
在泛型中类似 java 中的 ?。
1 2 3 4 5 scala> def testPrint (l: List [_]) = { | list.foreach(x => println(x)) | } testPrint: (l: List [_])Unit
在模式匹配中,可以用来代替 Java switch-case 表达方式中的 default 之外,还可以占位表示其他元素甚至类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 str match { case 1 => "one" case 2 => "two" case _ => "anything other than one and two" } expr match { case List (1 ,_,_) => "a list with three element and the first element is 1" case List (_*) => "a list with zero or more elements" case Map [_,_] => "matches a map with any key type and any value type" case _ => }
可以实现 Java import 语句中星号的作用,还能导入时做重命名,以及忽略某些类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 scala> import java.util.concurrent._ import java.util.concurrent._scala> import java.util.{ArrayList => al, _} import java.util.{ArrayList => al, _}scala> import java.util.{Timer => _, _} import java.util.{Timer => _, _}scala> import java.lang.Math ._ import java.lang.Math ._
3. 变量默认值初始化 用下划线可以自动在变量声明时,将其赋予默认的初始值。
1 2 3 4 5 6 7 8 scala> var name : String = _ name: String = null scala> var count : Int = _ count: Int = 0 scala> var avg : Double = _ avg: Double = 0.0
4. 访问元组(tuple) 下划线后面跟上数字 k,可以当作索引表示元组中的第 k 个元素。当要忽略元组中的某个值时,也可以用下划线代替它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 scala> val tuple = ("Tom" , 173.5 , Seq (22 ,66 ,88 )) tuple: (String , Double , Seq [Int ]) = (Tom ,173.5 ,List (22 , 66 , 88 )) scala> tuple._1 res1: String = Tom scala> tuple._2 res2: Double = 173.5 scala> tuple._3 res3: Seq [Int ] = List (22 , 66 , 88 ) scala> val (first, _, third) = tuple first: String = LMagics third: Seq [Int ] = List (22 , 66 , 88 )
5. 声明 setter 方法 Scala 中没有显式的 setter 方法,将 getter 方法的命名后加上一个下划线,当做 setter 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 scala> class Test { | private var pCount = 0 | def count = pCount | def count_= (c : Int ) = { | require(c > 0 ) | pCount = c | } | } defined class Test scala> val test = new Test () test: Test = Test @27 d5a580 scala> test.count = 7 test.count: Int = 7
6. 变长参数的转化 下划线与星号连用,可以将序列转化为变长参数的序列,方便调用变长参数的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 scala> def sum (args: Int *) = { | var result = 0 | for (arg <- args) result += arg | result | } sum: (args: Int *)Int scala> val sum1 = sum(7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ) sum1: Int = 84 scala> val sum2 = sum(7 to 14 : _*) sum2: Int = 84
7. 将方法转换成函数 函数在 Scala 中是一种对象实例,因此它可以赋值给变量,也可以作为参数。如果方法在赋值时直接写名称的话,编译器会认为是对方法的调用,因此会报没有参数列表的错误。在方法名称后加一个下划线,会将其转化为偏应用函数(partially applied function),就能直接赋值了。
1 2 3 4 5 6 7 8 9 10 11 12 scala> def twoSum (a: Int , b: Int ) = a + b twoSum: (a: Int , b: Int )Int scala> val twoSumFunc = twoSum _ twoSumFunc: (Int , Int ) => Int = <function2> scala> list foreach println _ 5 3 7 9 1
8. 定义偏应用函数 偏应用函数是不提供或者只提供部分参数调用时返回的函数,我们也可以用下划线来代替那些不提供的参数。
1 2 3 4 5 scala> def threeMult (a: Int , b: Int , c:Int ) = a * b * c threeMult: (a: Int , b: Int , c: Int )Int scala> val parThreeMult = (8 , _: Int , 42 ) parThreeMult: Int => (Int , Int , Int ) = <function1>
4. 上界(<:)、下界(>:)、协变(+)、逆变(-)
1. 上下界 常用在泛型中,类似 java 的 <S extends T>, <U spuer T>
S <: T
: 类型上界的定义,S 必须是类型 T 的子类或本身
U >: T
: 类型下界的定义,U 必须是类型 T 的父类或本身
2. 协变逆变 常用在泛型中,如 List[T],如果对于 A 是 B 的子类型,满足 List[A] 也符合 List[B] 的子类型,那么就称为 covariance(协变),相反,则称为 contravariance(逆变) 。 即,协变是指可以将子类集合可以转换成父类集合,符合里氏替换原则(子类型必须能够替换掉他们的基类型),逆变则是反过来。
1 2 3 4 5 6 7 8 9 10 11 12 class Animal {}class Bird extends Animal {}class Covariant [+T ](t:T ) {}val cov = new Covariant [Bird ](new Bird )val cov2:Covariant [Animal ] = covclass Contravariant [-T ](t:T ) {}val c: Contravariant [Animal ] = new Contravariant [Animal ](new Animal )val c2: Contravariant [Bird ] = c
3. 特殊类 1. Range
是一种数据结构,一种容器,是一种特殊的带索引的不可变的等差数字序列。
1. 声明 除了可以创造整数型序列,也可以是字符型、单精度浮点型
1 2 3 4 5 6 7 8 9 10 11 val r = new Range (1 ,5 ,2 )r.foreach(print(_)) val a1 = 1 to 5 by 1 val a2 = 1. to(5 ).by(2 ) val a3 = 1 until 5 val b = .5 f to 10.8 f by 0.5 f
4. 总览