i-Scala

一. 概览

scala : java语言的脚本化。

Scala 的类关系图

image-20180712141916222

数据类型注意点

1、 Any 是所有类的父类,包括值类型 AnyVal,和引用类型 AnyRef
2、 AnyVal 是所有值类型的父类,包括 Int,Double,Boolean,Unit 等等
3、 AnyRef 是所有引用类型的父类,包括 Null
4、 Null 是所有引用类型的子类
5、 Nothing 是所有类的子类
6、 Unit 类型只有一个实例,是(),相当于 java 中的 void,没有任何的实质意义
7、 Null 也只有一个实例,是 null,相当于 java 中的 null,能赋值给任何引用类型变量,不
能赋值给值类型变量

方法的返回值:

  • 如果没有显示定义返回值, 会返回 有可能返回 的 值 共同类型(父类)

定义方法

image-20180712161733886

定义函数

image-20180712232102657

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//变量
scala>var a = 100 //变量

//常量
scala>val a = 100 //常量,不能重新赋值。

//定义类型 //val 常量, 不能再重新赋值
scala>val a:String = "hello" ;

//操作符重载
scala>1 + 2
scala>1.+(2)

//scala方法,可以直接调用
scala>import scala.math._ //_ ===> * 下划线是通配的意思
scala>min(1,2)

//apply
scala>"hello".apply(1) //等价于xxx.apply()
scala>"hello"(1)

//条件表达式,scala的表达式有值,是最后一条语句的值。
scala>val x = 1 ;
scala>val b = if x > 0 1 else -1 ;

//Any 是Int和String的超类。

//类型转换
scala>1.toString()
scala>"100".toInt() //

//空值
scala> val y = () //y:Unit= ()类似于java void.
y: Unit = ()

//粘贴复制
// 有左大括号的话, 回车会直接换行
// 进入 paste 模式
scala>:paste
....
ctrl + d //结束粘贴模式

// scala 的编译
javac java
*.java --------> *.class -------->程序

//输出
scala>print("hello")
scala>println("hello")
scala>printf("name is %s , age is %d", "tom",12);

//读行
scala>val password = readLine("请输入密码 : ") ;

//查看帮助
scala>:help

二. 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 普通循环
var i = 0 ;
while(i < 10 ){
println(i) ;
i += 1;
}

===================================================================
// 99表格
var row = 1 ;
while(row <= 9 ){
var col = 1 ;
while(col <= row){
printf("%d x %d = %d\t",col,row,(row * col)) ;
col += 1 ;
}
println();
row += 1 ;
}

===================================================================
// 百钱买百鸡问题
// 100块钱能各买3种🐓, 各买多少种
// 公鸡:5块/只
// 母鸡:3块/只
// 小鸡:1块/3只

//公鸡
var cock = 0 ;
while(cock <= 20){
//母鸡
var hen = 0 ;
while(hen <= 100/3){
// 小鸡🐥
var chicken = 0 ;
while(chicken <= 100){
// 钱数
var money = cock * 5 + hen * 3 + chicken / 3 ;
// 个数
var mount = cock + hen + chicken ;
if(money == 100 && mount == 100){
printf("cock : %d , hen : %d , chicken : %d\n",cock,hen,chicken) ;
}
chicken += 3;
}
hen += 1;
}
cock += 1;
}


===================================================================
//for循环

// to
// 注意: <- 是写在一起的
scala> for (x <- 1 to 10){
println(x) ;
}

-------------------------------------
// until [1,...10)
// 左闭右开
for (x <- 1 until 10){
println(x) ;
}

// step 为2
for (x <- 1 until (10,2)){
println(x) ;
}


// 倒序打印
for (str <- (1 to 10).reverse){
println(str)
}

// 使用数组下标的方式进行打印
for (i <- 0 to arr.length - 1){
println(arr(i))
}

-------------------------------------
//scala没有break continue语句。可以使用Breaks对象的break()方法。
scala> import scala.util.control.Breaks._
scala> for(x <- 1 to 10) {if (x>8) break() ; print(x)} ;
eg: scala> for(x <- 1 to 10) { println(x); if(x == 5)break;}
12345


===================================================================
//for循环高级

//双循环,守卫条件
scala> for(i <- 1 to 3 ; j <- 1 to 4 if i != j ) {printf("i = %d, j = %d , res = %d \n",i,j,i*j);} ;

-------------------------------------
//yield,是循环中处理每个元素,产生新集合
scala>for (x <- 1 to 10 ) yield x % 2 ;

三. 定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 方式1
def add(a:Int,b:Int):Int = {
var c = a + b ;
return c ;
}

// 方式2
def add(a:Int,b:Int):Int = a + b

===================================================================

//scala实现递归

核心: n! = n * (n - 1)! // n 的阶乘 = n-1的阶乘, 并且 出口是 n=1
4! = 4 x 3!
4! = 4 x 3 x 2!
4! = 4 x 3 x 2 x 1!

//递归函数必须显式定义返回类型
scala> def fac(n:Int):Int = if(n == 1) 1 else n * fac(n-1) ;

===================================================================
//函数的默认值和命名参数
scala>def decorate(prefix:String = "[[",str:String,suffix:String = "]]") = {
prefix + str + suffix
}

// 如果都指定了默认值, 调用的时候 可以不传参数
// 也可以不指定参数名 传任意个数 的参数, 会从第一个开始匹配
def decorate(prefix:String="[[", str:String="👌", suffix:String="]]")={
prefix + str + suffix
}

----调用
scala>decorate(str="hello")
scala>decorate(str="hello",prefix="<<")

===================================================================

//变长参数 (就相当于可以传多个值)
def sum(a:Int*) = {
var s = 0;
for(x <- a) s += x;
s
}

sum(1,2,3,4)
sum (1 to 4:_*) // 将1 to 4当做序列处理
// 两者是一样的效果

sum(1 to 4) // wrong, 这样是错误的

------------------------------------------------
// 递归相加(跟上面变长参数循环遍历的效果一样)
def sum(args:Int*):Int = {if (args.length == 0) 0 else args.head + sum(args.tail:_*)}
----调用
sum (1 to 4:_*)
===================================================================

// 过程 (没有返回值,没有=号)
def out(a:Int){println(a)}

def out(a:Int)={println(a)}

def out(a:Int):Unit = {println(a)}

>> 以上3种方式等价

===================================================================
//lazy延迟计算

scala> lazy val x = scala.io.Source.fromFile("/Users/shixuanji/Documents/IDEs/iTerm2/scala/buyChicked.scala").mkString
x: String = <lazy>
scala> x
res63: String = "...这里就是加载出来的的文件内容"

===================================================================
//异常
scala>
try{
"hello".toInt;
}
catch{ //交给
case _:Exception => print("xxxx") ;
case ex:java.io.IOException => print(ex)
}

-----> 最简单的异常
scala> try { 1/0 } catch { case _: Exception => println("错啦.....") }
错啦.....
res76: AnyVal = ()

// _ 的意义
1> 通配相当于*
2> 1 to 10 :_* ,转成序列
3> case _:Exception => print("xxxx") ;

四. 数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 定长
---------------
java> int[] arr = int int[4] ;
scala>var arr = new Array[Int](10); //apply(10)
scala>var arr = Array(1,2,3,4); //推断
scala>arr(0) //按照下标访问元素

// 使用 +: 添加元素, 使用 ++: 添加数组, 结果是一个新数组
scala> val arr = Array(1,2,3)
arr: Array[Int] = Array(1, 2, 3)

scala> var arr2 = arr :+ 2
arr2: Array[Int] = Array(1, 2, 3, 2)

scala> arr2
res2: Array[Int] = Array(1, 2, 3, 2)

scala> arr
res3: Array[Int] = Array(1, 2, 3)


//变长数组
-------------------
scala>import scala.collection.mutable.ArrayBuffer
scala>val buf = ArrayBuffer[Int](); //创建数组缓冲区对象

//+=在末尾追加
-------------------
scala> buf += 3
res156: buf.type = ArrayBuffer(3)

scala> buf .+= (23)
res157: buf.type = ArrayBuffer(3, 23)

scala> buf ++= Array(4,5,6)
res158: buf.type = ArrayBuffer(3, 23, 4, 5, 6)


//trimEnd,从末尾移除元素
-------------------
scala>buf.trimStart(2)
scala>buf.trimEnd(2)

//remove按照索引移除
-------------------
scala>buf.remove(0)

//insert,在0元素位置插入后续数据
-------------------
scala>buf.insert(0,1,2)

//toArray
-------------------
scala>buf.toArray


=================================数组操作==================================
//数组操作
// 需求: 构造出20以内, 4的倍数的数组
// 方式1
scala> (for(x <- 1 to 10 if x % 2 == 0) yield x * 2).toArray
res107: Array[Int] = Array(4, 8, 12, 16, 20)

// 方式2
scala> Array(1 to 10:_*).filter(_ % 2 == 0).map(_ * 2)
res109: Array[Int] = Array(4, 8, 12, 16, 20)

==========================================
// map函数, 参数是一个函数, 函数的参数必须与调用者的参数构成一致
// 每次拿出一个参数出来算
'map': 把一批元素经过操作以后映射出另一批元素, kv 进, kv 出
// filter 函数, 同上
'filter': 过滤, 把不符合条件的元素过滤掉
==========================================

---------------------------------------------------------
//数组常用方法
--------------------
scala>arr.sum
scala>arr.min
scala>arr.max

//排序
--------------------
scala>import scala.util.Sorting._
scala>val arr = Array(1,4,3,2)
scala>quickSort(arr) //arr有序

//Array.mkString => array 转为 string
--------------------
scala> val arr = Array(3, 4, 14, 21)
arr: Array[Int] = Array(3, 4, 14, 21)

scala> arr
res164: Array[Int] = Array(3, 4, 14, 21)

scala> arr.mkString("<<",",",">>")
res165: String = <<3,4,14,21>>
===================================================================


//多维数组
--------------------
// 定义方式1
scala> var arr = new Array[Array[Int]](4)
arr: Array[Array[Int]] = Array(null, null, null, null)
scala> arr(0) = Array(1)
scala> arr(1) = Array(1,2)
scala> arr(2) = Array(1,2,3)
scala> arr(3) = Array(1,2,3,4)

scala> arr
res128: Array[Array[Int]] = Array(Array(1), Array(1, 2), Array(1, 2, 3), Array(1, 2, 3, 4))

// 定义方式2
//二维数组,3行4列
scala>val arr = Array.ofDim[Int](3,4)
//下标访问数组元素
scala>arr(0)(1)
scala>arr.length


//数组的遍历
--------------------
scala> a
res178: String = hello

scala> for(i <- 0 until a.length) println(i+":"+a(i))
0:h
1:e
2:l
3:l
4:o

// 拿到每个数组中的元素(跟上面的遍历结果一样)
--------------------
scala> arr
res179: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))

scala> for(i <- 0 until arr.length) println(i+":"+arr(i))
0:[I@36081062
1:[I@70c6f11a
2:[I@378953bd

//和java对象交互,导入转换类型,使用的隐式转换
--------------------
import scala.collection.JavaConversions.bufferAsJavaList
val buf = ArrayBuffer(1,2,3,4);
val list:java.util.List[Int] = buf ; // scala 语法中, 泛型时在 中括号中


// 打印引用类型
println(result.toBuffer) // 打印引用类型的值
println(result.mkString(",")) // 以',' 分隔符打印
println(arr2.mkString("<",":",">")) // 前后缀 和 分隔符 打印

println(foreach(println)) // 循环打印

五. Map 映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 // 不可变 immutable
=============================================================================
//scala.collection.immutable.Map[Int,String] =>不可变集合
scala>val map = Map(100->"tom",200->"tomas",300->"tomasLee")
map: scala.collection.immutable.Map[Int,String] = Map(100 -> tom, 200 -> tomas, 300 -> tomasLee)
//通过key访问value
scala>map(100)

注意:
1) 如果是 immutable 的 map 的 val 要改变, 只能赋值给新的 val , 添加只能用 + 号
2) 如果是 immutable 的 map 的 var 可以直接使用 +=, -=
val newmap = map + (4->"ttt")

// 可变 mutable
=============================================================================
// 直接定义 hashMap 并赋值
---------------------------------------------
import scala.collection.mutable.HashMap
var map1 = HashMap(1->22, "dd"->33) //注意, 这里字符串只能使用 双引号
$scala> map1
res145: scala.collection.mutable.HashMap[Int,Int] = Map(2 -> 33, 1 -> 22)
scala> map1("dd")
res197: Int = 33


// 先定义空hashmap
---------------------------------------------
scala> var map2 = new HashMap[Int,Int]
map2: scala.collection.mutable.HashMap[Int,Int] = Map()

scala> var map3 = HashMap[Int,Int]() // 这里其实就是调用了 apply()
map3: scala.collection.mutable.HashMap[Int,Int] = Map()


// hashMap 赋值
---------------------------------------------
注意: += / -= 会改变原值, + / - 不会改变原值,只会改变当次返回值
---------------------------------------------
///添加元素: += (k->v) 注意: 要与定义时类型一致
scala> map2 += (1->100,2->200)
res150: scala.collection.mutable.HashMap[Int,Int] = Map(2 -> 200, 1 -> 100)
====> 注意: 此时 mutable de var 的 '+=' 和 '+', 效果是一样的
=====> map2 = map2 + (1->100,2->200) // 这个写法是错误的, 要么用+, 要么用+=

///删除元素: -= k
scala> map2 -= 1
res151: scala.collection.mutable.HashMap[Int,Int] = Map(2 -> 200)

==> 注意: 如果key 一样, 会覆盖掉前面的赋值, 相当于修改
==> 当然, 也可以这样修改: >>> map2(1) = 500


//迭代map
---------------------------------------------
scala>for ((k,v) <- map) println(k + ":::" + v);

scala> for ((k,v) <- map) println(k +":::::" + v)
1:::::33
2:::::44
3:::::55

//使用yield操作进行倒排序(kv对调)
---------------------------------------------
scala> for ((k,v) <- map) yield (v,k)
res210: scala.collection.immutable.Map[Int,Int] = Map(33 -> 1, 44 -> 2, 55 -> 3)


// map方法:
此方法只能接受一个参数, 这个参数是函数
此参数函数, 也只能接受一个参数, 此参数的类型, 和数组中的元素类型一致
此参数函数最终会返回一个值, 值的类型可以自定义

val add1 = (x : Int) => x+1
arr.map(add1)

arr.map( (x : Int) => x+1 )
arr. map(x => x +1)
arr.map(_ + 1)


// 取值
map.get("xx") //没有的话就返回空
scala> m.getOrElse(0,"no") // 没有的话就返回后面指定的元素

六. 元组tuple, 最大Tuple22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 二元元祖 叫 对偶
---------------------------------------------
元组的定义: 用小括号包起来
---------------------------------------------
scala> val t = (1,"tom",12) ;
scala> t
res216: (Int, String, Int) = (1,tom,12)

scala> val t = (1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1)
t: (Int, String, Int, Int, String, Int, Int, String, Int, Int, String, Int, Int, String, Int, Int, String, Int, Int, String, Int, Int) = (1,tom,12,1,tom,12,1,tom,12,1,tom,12,1,tom,12,1,tom,12,1,tom,12,1)

scala> val t = (1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,3)
<console>:1: error: too many elements for tuple: 23, allowed: 22
val t = (1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,"tom",12,1,3)

注意: error: too many elements for tuple: 23, allowed: 22 元祖最多22


// 访问元组指定元
---------------------------------------------
==> 注意: 元祖序列从 1 开始
scala> val t = (1,2,3,4) ; //元组
scala>t._2
scala>t _2 (不推荐)

val (a,b,c) = t
==> 相当于一下声明了3个变量, a,b,c


//直接取出元组中的各分量
---------------------------------------------
scala> val t = (132,"d4",3)
t: (Int, String, Int) = (132,d4,3)

注意: 前后的元数必须相等
scala> val (a,b,c) = t
a: Int = 132
b: String = d4
c: Int = 3
==> 这里就相当于直接定义了 a,b,c 三个变量


//数组的zip
---------------------------------------------
//西门庆 -> 潘金莲 牛郎 -> 侄女 ,
scala> val hus = Array(1,2,3);
hus: Array[Int] = Array(1, 2, 3)

scala> val wife = Array(4,5,6,7)
wife: Array[Int] = Array(4, 5, 6, 7)

scala> hus.zip(wife)
res226: Array[(Int, Int)] = Array((1,4), (2,5), (3,6))

注意: 个数对不上的就砍掉了

七. OOP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// 定义类 & 基本操作
===============================================================
class Person{

// 定义变量, 私有类型, 必须初始化
// .class 中私有方法查看: javap -private xxx.class
// getter/setter 也私有
private var id = 0;

// p.name => getter
// p.name_=(xx) => setter
// p.name = xx => setter
// 生成私有属性, 和共有的 getter/setter 方法
var name = "tom";

// val 只有 getter, 没有setter, 定义的是 val 常量
val age = 100;
def incre(a:Int) = {id += a}

//如果定义时,没有(),调用就不能加()
// 有的话, 调用的时候就可加可不加
def current() = id
}

------------------------
->调用

scala>var p = new Person();
scala>p.current()
scala>p.current
scala>p.incr(100)
scala>p.name
scala>p.name_=("kkkk")
scala>p.name = "kkkk"


// private[this]作用,控制成员只能在自己的对象中访问。 (对象私有)
===============================================================
1) Scala中(JavaC++ 也一样), 方法可以访问该类的所有对象的私有字段
2) private[this], 是 Counter 类的方法, 只能访问到当前对象的 value 方法, 而不能访问同样是 Counter 类型的其他对象的该字段.
3) 这样的访问被称为 对象私有的
4) 对于类私有的字段, Scala 生成私有的 getter 和 setter 方法;
但对于对象私有的字段, Scala 根本不会生成 getter 和 setter 方法

class Counter{
private[this] var value = 0 ;
def incre(n:Int){value += n}
// 类会定义失败, 下面这句不能访问别类对象的 value
def isLess(other:Counter) = value < other.value ;
}


// 定义BeanProperty注解 :TODO
------------------------------------------------------------------
...



// 构造函数
===============================================================
> 辅助构造
----------------------
>> 定义
class Person{
var id = 1 ;
var name = "tom" ;
var age = 12;

//一个辅助构造器
def this(name:String){
this(); // 调用主构造器
this.name = name ;
}
//另一个辅助构造
def this(name:String,age:Int){
//调用前一个辅助构造器
this(name) ;
this.age = age ;
}
}

>> 使用
scala> var p = new Person("tm")
p: Person = Person@2492f6fb

scala> p.name
res9: String = tm

scala> p = new Person("jr",23) // 注意: 此 p 非上面的 p 了
p: Person = Person@2536edc3

scala> p.name
res11: String = jr

scala> p.age
res12: Int = 23



> 主构造函数
---------------------------------------------
//val ===> 只读
//var ==> get/set
//none ==> none

// 注意: id 前面没有修饰的话, 只有在调用后才升级为成员变量, 否则在 .class 文件中不会出现
class Person(val name:String, var age:Int, id :Int){
def hello() = println(id)
}

>>编译后生成的文件
javap -private Person.class -> 显示编译后的 private 成员

public class Person { // id 调用后才升级为成员变量
private int age;
private final int id;
public java.lang.String name(); // getter
public int age(); // getter
public void age_$eq(int); // setter
public void hello();
public Person(java.lang.String, int, int);
}


// object
===============================================================
说明:scala没有静态的概念,'如果需要定义静态成员,可以通过object实现。'
编译完成后,会生成对应的类,方法都是静态方法,非静态成员对应到单例类中

// 单例类以Util$作为类名称。
// 静态方法类 Util 为类名称.
scala>object Util{
//被编译为单例类中.(Util$)
private var brand = "benz" ;
//被编译为 单独Util 类中的 静态方法
def hello() = println("hello world");
}

➜ scala javap -private Util
Compiled from "util.scala"
public final class Util {
public static void hello();
}
➜ scala javap -private Util$
Compiled from "util.scala"
public final class Util$ {
public static Util$ MODULE$;
private java.lang.String brand;
public static {};
private java.lang.String brand();
private void brand_$eq(java.lang.String);
public void hello();
private Util$();
}



// 伴生对象(companions object)
------------------------------------------------------------------
1. 类名和object名称相同,而且必须在一个scala文件中定义。
2. 编译后, 会产生2个文件, Car.class Car$.class
3. 静态方法会被编译到 Car.class 中去, 静态方式可直接用类调用

class Car{
def stop() = println("stop....")
}

object Car{ // 伴生对象, 目的就是为了产生静态方法
def run() = println("run...")
}
------------
> 编译后
➜ scala javap -private Car
Compiled from "companionsObject.scala"
public class Car {
public static void run();
public void stop();
public Car();
}
➜ scala javap -private Car$
Compiled from "companionsObject.scala"
public final class Car$ {
public static Car$ MODULE$;
public static {};
public void run();
private Car$();
}

4. 因为 main 函数是静态方法, 所以写在伴生对象中

class Person(val name:String, var age:Int, id : Int) {
def hello() = println(id);
}

object Person {
def main(args:Array[String]) = println("hello world");
}

➜ scala scala main.scala // 直接 scala xx.scala 会先编译再运行
hello world


// 抽象 & 静态
===============================================================
➜ 抽象 & 静态 test

➜定义类

// 抽象类
abstract class Dog {
def a():Unit
}

// object等价于java中的静态。
object Jing8 extends Dog {
// 重写方法
override def a():Unit= println("hello")
}

class Zangao extends Dog {
override def a():Unit = println("老子是个🐶??")
}

➜ 调用
scala> Jing8.a // 静态方法调用


scala> Jing8.a
hello

scala> var za = new Zangao() // 类创建对象调用
za: Zangao = Zangao@77505c0e

scala> za.a
老子是个🐶??



// apply
===============================================================
1) 使用
// 定义:
object Util{
def apply(s:String) = println(s) ;
}
// 调用: 下面2者是一个意思
Util("hello world");
Util.apply("hello world");
> 运行结果: hello world


2) 注意点
// 注意一下2者的区别
scala> var arr = Array(10)
arr: Array[Int] = Array(10)

scala> arr
res18: Array[Int] = Array(10)

scala> var arr = new Array(10)
arr: Array[Nothing] = Array(null, null, null, null, null, null, null, null, null, null)


// 终端编译运行 scala文件
===============================================================
scalac编译scala文件,产生class文件。
------------------------------------
cmd>scalac xxxx.scala

运行class程序
--------------------
cmd>scala Person

一步到位
-------------------
cmd>scala Person.scala



// trait (类似于 Java 中的 interface )
===============================================================
traint HelloService{
}


//包对象,编译完之后生成以 /a/a1/aa1/people/xxx.class..., 一层一层文件夹
===============================================================
package a.a1.aa1;
package object people {
val name = "hello world";
}


//约束可见性。
-----------------------
private[package|this]


// 包的导入
--------------
import java.io.Exception
import java.io.{A,B,C} //同一包下的不同类, 可以用大括号包起来
import java.io.{A => A0} //别名

八. 继承 inheritance

extends

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
继承/扩展
-------------------------------
class Dog extends Animal{
//重写,覆盖
//overload
override def run()={...}
}



继承实例
------------------------------
$scala>class Animal(val name:String){}
$scala>class Dog(name:String,val age:Int) extends Animal(name){}
$scala>class Duck(override val name:String, val age:Int) extends Animal(name:String)


注意: 如果在构造里为继承的父类传参, 创建的子类对象直接会有值
scala> class Duck(name:String, val age:Int) extends Animal("aa")
defined class Duck

scala> var dd = new Duck("cc",32)
dd: Duck = Duck@12a63c27

scala> dd.name
res33: String = aa


类型检查和转换
------------------------------
$scala>class Animal{}
$scala>class Dog extends Animal{}
$scala>val d = new Dog();
$scala>d.isInstanceOf[Animal] //true,===> instanceOf
$scala>val a = d.asInstanceOf[Animal] //强转,===> (Animal)d

//得到对象的类 对象类型 得到类型
$scala>d.getClass //d.getClass(); 获取对象类型
$scala>d.getClass == classOf[Dog] //精确匹配

九. abstract , trait, file, apply, 操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

//抽象类 abstract
================================================
$scala>abstract class Animal(val name:String){
//抽象字段,没有初始化。
val id:Int ;
//抽象方法,没有方法体,不需要抽象关键字修饰。
def run() ;
}



// scala类型树 :TODO
================================================
Any
|
/|\
|------------AnyVal <|------Int|Boolean|...|Unit
|------------AnyRef <|------class ...



// 读取文件 file
================================================
-----------in idea
import scala.io.Source ;
object FileDemo {
def main(args: Array[String]): Unit = {
val s = Source.fromFile("d:/hello.txt") ;
val lines = s.getLines();
for(line <- lines){
println(line)
}
}
}


---------in terminal
scala> scala.io.Source.fromFile("/Users/shixuanji/Documents/IDEs/iTerm2/scala/util.scala").mkString
// 下面是上面执行的结果
res34: String =
object Util {
private var brand = "benz";
def hello() = println("hello world");
}


//通过正则 (具体的查看 dash 的 jdk)
\s : 空白字符:[ \t\n\x0B\f\r]
\S : 非空白字符:[^\s]

val str = Source.fromFile("/hello.txt").mkString
val it = str.split("\\s+") // 过滤掉所有不可见字符分割
for(i <- it){
println(i)
}


// trait 接口
================================================
> java中, 实现接口, 用implement , scala 中用 extends
> 如果只有一个trait使用extends进行扩展,如果多个,使用with对剩余的trait进行扩展。

trait logger1{
def log1() = println("hello log1");
}

trait logger2{
def log2() = println("hello log2");
}

> trait(接口)之间也可以存在扩展。
class Dog extends logger1 with logger2{
}


//自身类型 :TODO 还不明白是啥意思, 有空看看 书 : 10.13 Self Types & 18.10
================================================

trait logger{
this:Dog =>
def run() = println("run....")
}
trait Dog {}
trait Jing8 extends Dog with logger{}
class Cat extends logger{}


// 操作符
================================================
//中置操作符
scala> 1 + 2 //
scala> 1.+(2) //

//单元操作符
scala> 1 toString //+: -:取反 !:boolean取反 ~:按位取反

//赋值操作符
$scala>+= , -= , *=, /=


//:表示右结合,只有:结尾的操作符是右结合,优先级从右侧开始
----> 用于构造列表的操作符 :: 是右结合的
scala>val l = Nil //构造空集合.
scala>1::2::Nil //1::(2::Nil), 先创建包含2的列表, 这个列表又被作为为嘛频道以1为头部的列表中
scala>Nil.::(2)


// apply()/update() --> 其实就是在等号两侧的问题
================================================
var arr = Array(100) //Array.apply(100);
arr(0) = 200 //arr.update(0,1234)

// apply(), 接受的是属性参数, 返回的是对象, 内部就是 new 了一个对象
//unapply(),是apply的逆向过程,接受的是对象, 返回的是参数(对象中的属性值), 如果用一个元祖中, 传入相应的变量名, 就相当于给这些变量赋值了
//定义类
------------
class Fraction(val n:Int,val d:Int){
}

object Fraction{
//通过
def apply(n : Int,d:Int)= new Fraction(n,d)
//逆向过程
def unapply(f:Fraction) = Some(f.n,f.d)
}
-------------
// 因为定义了 apply, 所以直接调用 Fraction(1,2) 就会创建一个对象
scala> val f = Fraction(1,2) //apply(...)
> 执行结果
scala> f
res254: Fraction = Fraction@30d2895e

// 把定义的函数 还原成 Fraction, 此时, 就相当于定义了 a,b
scala> val Fraction(a,b) = f //unapply(...)
> 执行结果
a: Int = 1
b: Int = 2

十. 高阶函数

—> 函数 Function 和 方法 Method 的区别, 见这里

查看函数: 直接输入函数名

查看方法: 输入方法名之后, 按 tab 键提示, 也会展示方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
基本函数定义
参数&类型 => 实现
val f1 = (x: Int, y: Int) => x + y
val f2 = (a:Double)=>a*a

//定义高阶函数 例子1
================================================================
// f 指参数, f的类型是 (Double)=>Double 函数
// 这里的参数 f 可以是任何接受 Double 并返回 Double 的函数, valueAtOneQuarter 函数, 将计算那个函数在 0.25位置的值
// 注意: 这里只接受一个 Double 参数
import scala.math._
def valueAtOneQuarter(f:Double=>Double) = f(0.25)

// 调用
// 往单函数参数的函数 的 参数中, 传一个函数, 此函数符合 (Double)=>Double) 的特征, 然后往此函数中, 传值 0.25
val f2 = (a:Double)=>a*
valueAtOneQuarter(f2) // 执行时, 会把后面的 0.25传入到
valueAtOneQuarter(cail _) // cail 函数: 大于传入值的最小整数


// 高阶函数例子2
================================================================
// 参数 = 函数体(函数)
// 参数 => 返回值
// 方法的实现是一个函数, 此函数有自己定义的参数, 有从方法体中传来的参数
def mulby(factor : Double) = (x:Double) => x * factor
mulby(2)
scala> def mulby(factor : Double) = (x:Double) => x * factor
mulby: (factor: Double)Double => Double

scala> mulby(2)
res9: Double => Double = $$Lambda$1165/745462106@3d3e9163

scala> mulby(2)(2)
res10: Double = 4.0

>>> 接下来把次mulby 方法, 转成函数试试
scala> val f_mulby = mulby _
f_mulby: Double => (Double => Double) = $$Lambda$1364/1154393787@6307382
>>> 调用方式还是一样的
f_mulby(2)(2)
-------------------------
scala>def multi(n:Int) = n * 2
scala>def f = multi _ // _ 表示:把multi 转为函数
scala>Array(1,2,3,4).map(f)


➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜

//匿名函数
scala>(n:Double)=>3 * n // 匿名函数
scala>val f = (n:Double)=>3 * n // 变量引用匿名函数
scala>Array(1,2,3,4).map( (x) => x * 3 ); //把匿名函数传递给 map 方法


➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜

//定义高阶函数 例子3
==============================================================================
// 定义 call 方法, 其中2个参数也为函数
def call(a:Int, b:Int, f1:(Int,Int)=> Int, f2:(Int,Int)=> Int) = {
if(a > 0) f1(a,b);
else f2(a,b);
}
>>>> call: (a: Int, b: Int, f1: (Int, Int) => Int, f2: (Int, Int) => Int)Int

// ------->>>>>>>>>>> 定义方法, 再把方法转为函数
// 定义2个参数的方法
def add(a:Int,b:Int) = a+b
def sub(a:Int,b:Int) = a-b

// 方法转为 f1, f2 (当然, 也可以直接定义函数)
val f1 = add _
val f2 = sub _

// ------->>>>>>>>>>> 直接定义函数
scala> val f1 = (a : Int, b : Int) => { a + b }
f1: (Int, Int) => Int = $$Lambda$1388/1164150759@4d41b630

scala> val f2 = (a : Int, b : Int) => { a - b }
f2: (Int, Int) => Int = $$Lambda$1389/1260221930@37dc38cc


// 调用, 可以用f1,f2, 也可以直接使用方法名调用, 会默认转为函数 :TODO 了解原理
call(-1,2,f1,f2)
call(1,2,add _, sub _)
call(1,2,add,sub)



// call 函数提升
============================================================
需求: 以 call 函数的返回值3为系数, 然后传另一个数 x 到 函数y = 3 * x 中, 得到 y
------------------------------------------------------------
val f = call(1,2,f1,f2)
f(100) = 300 ;
call(1,2,add _,sub _)(100) = 300

-->> 定义
def call(a:Int,b:Int,f1:(Int,Int)=>Int,f2:(Int,Int)=>Int)= {
var n = 0 ;
if(a > 0) n = f1(a,b) ;
else n = f2(a,b) ;
// 定义方法
def multi(x:Int) = x * n ;
// 转为函数
multi _
}

call: (a: Int, b: Int, f1: (Int, Int) => Int, f2: (Int, Int) => Int)Int => Int

➜ 调用
scala> call(1,2,add _, sub _)(100)
res4: Int = 300

➜ 也可以在这里直接调用函数, 传的是函数的实参, 函数的实现:
// f1 的实现是 a+b, f2 的实现是 a-b, 而调用f1或f2 在 call 方法定义的时候
// 就已经指定了, 而参数也由前面的 a, b 传进来, 所以这里就可以直接调用了.
// 此call方法的返回值是一个函数, 此函数需要2个参数, 一个是前面的执行结果
// 一个是需要调用者传进来

// 这里也可以把 call方法 的返回值赋值给一个 函数变量, 再给这个函数变量传值
val f = call(1,2,(a:Int,b:Int) => a+b,(a:Int,b:Int) => a-b)
scala> f(100)

也可以直接在后面接上 100, 直接传参
call(1,2,(a:Int,b:Int) => a+b,(a:Int,b:Int) => a-b)(100)
res7: Int = 300


// 类型参数可以去掉, 因为使用的参数可以自动推导出参数的类型
call(1,2,(a:Int,b:Int)=>a + b , (a:Int,b:Int)=> a- b)(100)
// 精简过后
call(1,2,(a,b)=>a + b , (a,b)=> a- b)(100)

➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜ ➜➜➜➜➜➜➜➜➜➜➜➜➜➜


//函数推断
// 很显然, 此方法参数是一个函数, 函数只有一个参数, 参数\返回值都是 Double 类型
// 注意: 里面的函数是 形参, 也就是说 只是顶一个一个 f 函数, 参数&返回值类型为 Double, 并没有定义实现, 在传函数的时候, 要给出实现
def valueAt(f:(Double)=>Double) = f(0.25)
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
valueAt((x:Double)=>x * 3) //定义类型
valueAt((x)=>x * 3) //推断类型
valueAt(x=>x * 3) //省略()
valueAt(3 * _) //参数在右侧出现1次,就可以使用_代替。

//高级函数
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
scala> val arr = Array(1,2,3,4)
scala> arr.map(2 * _); //每个元素x2
scala> arr.map((e:Int)=> e * 2); //每个元素x2
scala> arr.map(_ * 2); //每个元素x2
scala> arr.filter(_ % 2 == 0) // 过滤出集合中的偶数
res55: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4)


// 其它的简单应用
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
// 在元素 * 3前先打印
scala> Array(1,2,3).map(e => {println(e); e * 3})
1
2
3
res56: Array[Int] = Array(3, 6, 9)

// filter 过滤
scala> Array(1,2,3,4).filter(e => e%2 == 0)
res14: Array[Int] = Array(2, 4)

// 1-10 先扩大3倍, 再过滤出偶数
scala> Array(1 to 10:_*).map(3 * _).filter(_ % 2 == 0)
res16: Array[Int] = Array(6, 12, 18, 24, 30)


//输出三角形 foreach 函数
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
scala>(1 to 9).map("*" * _).foreach(println)
scala>(1 to 9).map("*" * _).foreach(println _)
scala>(1 to 9).map("*" * _).foreach(println (_))
scala> Array(1 to 9:_*).map("*" * _).foreach(println _)

// reduceLeft / reduceRight 函数
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
//reduceLeft,由左至右, 每次进2个参数
val r = (1 to 10)
scala> r.reduceLeft(_ + _)
scala> r.reduceLeft(_ - _)
...
→ 执行流程
//1,2,3 ==> (1 - 2) -3) = -4

MR:MapTask + reduceTask,映射化简.

//reduceRight,由右至左
scala> r.reduceRight(_-_)
...
→ 执行流程
//1,2,3 ==>1 - (2 - 3)= 2
//1,2,3,4 ==> 1 - (2 - (3 - 4)) = -2
//1,2,3,4 ==> 1 - (2 - (3 - 4)) = -2

十一. 柯里化

概念: 以逻辑学家 Haskell Brooks Curry 的名字命名

将原来接受2个参数的函数, 变成新的接受一个参数的函数的过程.

新的函数返回一个以原有第二个参数作为参数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
→ 原函数
scala>def mul(a:Int,b:Int) = a * b;
scala>mul(1,2)

→ 柯里化
scala>def mulone(a:Int) = {(x:Int) => a * x ;}
scala>mulone(1)(2)

→→→→→→→ 柯里化测试
scala> def mulone(a:Int) = {(x:Int) => a * x}
mulone: (a: Int)Int => Int

// 首先传入一个参数, 得到的是另一函数 x:Int => x * 2 (也就是原方法的方法体)
scala> def f = mulone(2)
f: Int => Int

// 此时接着再传入参数 4, 得到 4*2 => 8
scala> f(4)
res33: Int = 8

// 直接传入2个参数可直接调用此方法, 返回结果
scala> mulone(2)(4)
res34: Int = 8

与柯里化相关的知识点(方法向函数的转换)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1) 多个参数的方法可以转换为多元函数
-------------------
scala> def plus(x: Int, y: Int): Int = x + y
plus: (x: Int, y: Int)Int

scala> plus _
res63: (Int, Int) => Int = $$Lambda$1495/772136419@16b54416

2) 多个参数的方法变成柯里函数 ---> 方法定义的时候, 不同的参数用 '()' 分开
---------------------
scala> def plus(x: Int)(y: Int): Int = x + y
plus: (x: Int)(y: Int)Int

scala> plus _
res64: Int => (Int => Int) = $$Lambda$1496/662093445@51927988

十二. 控制抽象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 类似于 OC 中的 block, 此 block 无参数无返回值 :TODO 是控制
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
1) 定义过程,启动分线程执行block代码. 方法的参数是一个 block 无参无返函数
def newThread(block: () => Unit) {
new Thread() {
override def run() {
block();
}
}.start();
}
-----------------
2) 调用 newThread方法, 并给 block 传值 'newThread(()=>{...})'
newThread(() => {
(1 to 10).foreach(e => {
val tname = Thread.currentThread.getName();
println(tname + " : " + e);
})
}
);
-------打印结果----------
scala> Thread-3 : 1
Thread-3 : 2
Thread-3 : 3
Thread-3 : 4
Thread-3 : 5
Thread-3 : 6
Thread-3 : 7
Thread-3 : 8
Thread-3 : 9
Thread-3 : 10

➜➜➜➜➜➜➜➜➜➜➜➜➜
PS: 在 定义方法的时候, 可省略'newThread(()=>{...})'前面的括号, 因为没有参数
在调用方法, 写 block 中的内容时 'newThread(() => {})', 可以直接写大括号{}中的代码逻辑, 其实这玩意儿就是 语法糖

十三. 集合

List 集合

List 在添加元素时注意点,详细代码见下面:

  • 使用 +::=添加单个元素时, :必须靠着 list 一侧, + 必须靠着 单个元素
  • 如果2边都是 list 集合, 必须用 ++:或者 ::: 或者 ++
  • 不管是 +: , :+ , ++:, 都不会改变原 list 的值
  • 要添加的 元素 / list 在原 list 的哪边, 就添加到 list 的 那边
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//Nil (List空集合)
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
scala> 1::2::Nil
res71: List[Int] = List(1, 2)

scala> var l1 = 1::2::Nil
l1: List[Int] = List(1, 2)

scala> l1
res72: List[Int] = List(1, 2)

scala> 9::l1
res73: List[Int] = List(9, 1, 2)


// List 求和
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
方式1-递归
-----------
定义>
def sum(list:List[Int]) : Int = {
if(list == Nil) 0 else list.head + sum(list.tail)
}

sum: (list: List[Int])Int

调用>
scala> val list = 1::2::3::4::Nil
list: List[Int] = List(1, 2, 3, 4)

scala> sum(list)
res41: Int = 10

方式2-模式匹配
-----------
其实本质上也是递归
定义>
def sum(list:List[Int]) : Int = list match {
case Nil => 0
case a::b => a + sum(b)
}

注意: ::将列表 析构 成头部和尾部
递归之所以那么自然, 因为列表的尾部正好又是一个列表
-------------------------------------------------------
scala 类库的 sum
List(2,3,4).sum


// List 添加元素
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
注意点: 1) 使用 +: 或 := 添加单个元素时, : 必须靠着 list 一侧, + 必须靠着 单个元素
2) 如果2边都是 list, 必须用 ++:
3) 不管是 +: :+ ++:, 都不会改变原 list 的值
4) 要添加的 元素 / list 在哪边, 就添加到数组的哪边
scala> var list2 = 1::2::3::5::4::Nil
list2: List[Int] = List(1, 2, 3, 5, 4)

scala> list2
res46: List[Int] = List(1, 2, 3, 5, 4)

scala> list2 :+ 3
res81: List[Int] = List(1, 2, 3, 5, 4, 3)

scala> 3 +: list2
res82: List[Int] = List(3, 1, 2, 3, 5, 4)

scala> list2
res88: List[Int] = List(1, 2, 3, 5, 4)

scala> list2 ++: List(99)
res86: List[Int] = List(1, 2, 3, 5, 4, 99)

scala> List(78) ++: list2
res87: List[Int] = List(78, 1, 2, 3, 5, 4)

// ++ 添加 实现2集合合并
scala>val l1 = List(1,2)
scala>val l2 = List(3,4)
scala>l1 ++ l2 ++ 与 :: 效果相同 // 是在l1的后面加上l2
scala>l1 ++: l2 ++: 与 ::: 效果相同 // 是在 l2的前面加上l1

Set 集合

注意:

  • 不可变 Set 添加的是 元祖, 使用+= 产生新集合, 自身无法改变, 可以赋值给新的常量 val
  • 可变 Set 也可以使用 += 添加 元祖, 改变自身, 还可以使用 ++= 添加其他集合, 比如 List, Array, Range(1 to 10) 等…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Set 可变集合的操作(默认)
------------------------------------------------------------
// Set 添加成员(元祖, 会自动去重, 无序)
scala>val set = Set(1,2,3)
scala>set + (1,2,3,5)
scala>set - (1,2,3,5)

scala>val s1 = Set(1,2,3)
scala>val s2 = Set(2,3,4)
scala>s1 | s2 //并集
scala>s1 & s2 //交集
scala>s1 &~ s2 //差集(1,2,3) - (2,3,4) = (1)


// Set 不可变集合的操作
------------------------------------------------------------
# 导包
scala>import scala.collection.mutable.{Set => MSet}

// 使用 += 添加元祖
scala> mset += 3
res129: mset.type = Set(0, 9, 45, 1, 2, 3, 10, 4, 98, 5, 6, 7, 43, 😎

scala> mset += (24,25,26)
res132: mset.type = Set(0, 9, 45, 1, 2, 24, 3, 10, 25, 4, 98, 26, 5, 6, 21, 7, 43, 😎

// 使用 ++= 添加 Array, List, Range...
scala> mset ++= Array(3,45)
res125: mset.type = Set(0, 9, 45, 1, 5, 2, 6, 3, 10, 7, 4, 😎

scala> mset ++= List(43,98)
res128: mset.type = Set(0, 9, 45, 1, 2, 3, 10, 4, 98, 5, 6, 7, 43, 😎

scala> mset ++= (0 to 10)
res123: mset.type = Set(0, 9, 1, 5, 2, 6, 3, 10, 7, 4, 😎

其他的一些操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 主要是 ArrayBuffer的
------------------------------------------------------------
scala> import scala.collection.mutable._
import scala.collection.mutable._

scala> val buf = ArrayBuffer(1,2,3)
buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

scala> 2 +=: buf
res138: buf.type = ArrayBuffer(2, 1, 2, 3)

// 提取前2个元素, buf 本身不变
scala> buf.take(2)
res139: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 1)

// 删除前2个元素, buf 本身不变
scala> buf.drop(2)
res141: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 3)

scala> buf
res142: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 1, 2, 3)

// 在指定位置进行切割,形成两个新集合。
scala> buf.splitAt(2)
res143: (scala.collection.mutable.ArrayBuffer[Int], scala.collection.mutable.ArrayBuffer[Int]) = (ArrayBuffer(2, 1),ArrayBuffer(2, 3))


scala> val b1 = ArrayBuffer(1,2,3)
scala> val b2 = ArrayBuffer(3,4,5,6)

// 舍弃掉少的
scala> b1.zip(b2)
res145: scala.collection.mutable.ArrayBuffer[(Int, Int)] = ArrayBuffer((1,3), (2,4), (3,5))

// b1不够, 用-1补, b2不够, 用-2补
scala> b1.zipAll(b2,-1,-2)
res146: scala.collection.mutable.ArrayBuffer[(Int, Int)] = ArrayBuffer((1,3), (2,4), (3,5), (-1,6))

//元素和自己的索引形成tuple.,元素在前, 索引在后
scala> b1.zipWithIndex
res147: scala.collection.mutable.ArrayBuffer[(Int, Int)] = ArrayBuffer((1,0), (2,1), (3,2))

scala> b1.zip(b2).zipWithIndex
res148: scala.collection.mutable.ArrayBuffer[((Int, Int), Int)] = ArrayBuffer(((1,3),0), ((2,4),1), ((3,5),2))


// 左右折叠
------------------------------------------------------------
//左折叠
scala> List(1,7,2,9).foldLeft(0)(_-_)
res87: Int = -19
(0 - 1) - 7 - 2 - 9 //-19


//右折叠
scala> List(1,7,2,9).foldRight(0)(_-_)
res88: Int = -13
1 - (7 - (2 - (9 - 0))_ //-13

十四. 模式匹配 & 偏函数

1. 字符串匹配

1
2
3
4
5
6
7
8
9
10
scala> val x = '9'
x: Char = 9

scala> x match{
| case '+' => print("++++")
| case '_' => print("-----")
| case _ if Character.isDigit(x) => print("is number!")
| case _ => print("...")
| }
> is number!

2. 匹配类型,x类型定义成判断类型的共同超类。

1
2
3
4
5
6
7
8
9
scala>    val x:Any = "123"
x: Any = 123

scala> x match{
| case b:Int => print("is Int") ;
| case a:String => print("is String") ;
| case _ => print("is Int") ;
| }
is String

3. 匹配数组数据

1
2
3
4
5
6
7
8
9
10
11
12
13
scala> val arr = Array(0,1,2)
arr: Array[Int] = Array(0, 1, 2)

scala> arr match{
| //匹配arr中只有 0
| case Array(0) => println("arr 中只含有0")
| //匹配是否两个元素
| case Array(x,y) => println("有两个元素")
| //是否从0开始
| case Array(0,_*) => println("从0开始")
| case _ => println("有0") }

// 还可以匹配其它复杂数据类型中某个位置上的值.

4. 偏函数

把模式匹配抽出来变成函数了

1
2
3
4
5
6
7
8
9
10
11
12
13
 ---定义
val f : PartialFunction[Char, Int] = {
case '+' => 1;
case '-' => -1;
case _ => 0
}

---测试
scala> f('x')
res106: Int = 0

scala> f('+')
res107: Int = 1

十五. 样例类

关键字 : case

主要用于模式匹配.

内置了apply和unapply方法,还有串行化等接口。

创建对象时不需要使用new.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 // 创建样例类
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
abstract class Dog{}
case class Jing8(name:String) extends Dog{}
case class Shapi(age:Int) extends Dog{}

scala> val d = Jing8("tom") // 可以直接创建, 因为内置了 apply

d match{
case Jing8(name) => print("是Jing8 : " + name);
case Shapi(age) => print("是Shapi : " + age);
case _ => print("aishiuihsui");
}
--> 运行结果:
Jing8: tom


// 查看 .class 文件
// 发现有 apply, unapply, implements scala.Serializable 等
--------------------------------------------------
➜ scala javap -private Jing8$.class
Compiled from "dog.scala"
public final class Jing8$ extends scala.runtime.AbstractFunction1<java.lang.String, Jing8> implements scala.Serializable {
public static Jing8$ MODULE$;
public static {};
public final java.lang.String toString();
public Jing8 apply(java.lang.String);
public scala.Option<java.lang.String> unapply(Jing8);
private java.lang.Object readResolve();
public java.lang.Object apply(java.lang.Object);
private Jing8$();
}




// 密封样例类
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
子类和父类必须定义在同一文件中。
sealed abstract class Dog{}
case class Jing8(name:String) extends Dog{}
case class Shapi(age:Int) extends Dog{}

十六. 泛型

1. 泛型的定义 & 上下界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Java 中常用的泛型
List<String>
Map<String,String>

// Scala 中的泛型
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜

//类的泛型,定义泛型类
class Pair[T,S](one:T,second:S); //定义泛型类
val p = new Pair[String,Int]("tom",12); // 创建泛型对象
val p = new Pair("tom",12); //类型推断

//方法泛型
def getMiddle[T](arr:Array[T]) = arr(arr.length / 2);
-> 可以传入任意类型的 Array

➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
//泛型的上界,T必须是Dog的子类。
def run[T <: Dog](d:T) = println("hello")
// 定义下界,T必须是shapi的父类。有问题: 测试是通配的, 传啥都可以 :TODO
def run2[T >: Shapi](d:T) = println("hello")

<: //上界,子类
>: //下界,父类 ???
<% // A <% B,A能够隐式转换成B
T <:Dog >:Cat //约束多个条件。

// 视图界定
[T <: Comparable]

2. 泛型的型变 :TODO 不懂

1
2
3
4
5
6
7
Friend[+Dog]            //协变, 如果 A是 B的子类, 那么ListA 也是  ListB 的子类
Friend[-Dog] //逆变

Friend[-Dog] // 当采用 -号 约束时, 原本 Friend[NafangShapi] 为 Friend[Shapi] 的子类的, 现在变成父类

Friend[Shapi]
Friend[NafangShapi]

十七. 隐式转换 implicit

隐式转换函数:使用 **implicit** 修饰的具有一个参数的函数。 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 定义隐式转换函数 
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
// 定义了之后, 调用 run(100) , 此100会自动隐式的转为 dog 对象
// 当调用一个对象不存在方法时, 会寻找是否能隐式转换为其它对象
// 需要当前代码上下文可见

implicit def int2Dog(n:Int) = Shapi(n); //定义

def run(d:Dog) = print("hello world");

run(100) ; //调用run 方法, 会直接调用隐式转换函数。 把100作为参数, 创建 Shapi 对象


// 定义隐式单例对象 
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
object DogUtil{
//定义隐式转换函数
implicit def str2Dog(s:String) = Jing8(s) ;
}

--- 使用
def run3(d:Dog) = println("hello world");
import DogUtil._ //
run3("tom")


//参数默认值
---------------------------------------------
def decorate(prefix:String = "[[[",c:String,suffix:String="]]]") = ...
decorate(c= "hello world")

//  隐式参数(默认参数) 
// 参数为隐式的参数, 回去找此参数, 如果参数有默认值, 就不需要对此参数赋值
➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜➜
object DogUtil2{
implicit val dog = Jing8("tomas") ;
}

import DogUtil2._
def run4(implicit dog:Jing8) = println("hello : ") ;

run4; // 注意, 如果不想传参数, 想要调用隐式的默认值, 后面不需要加 (). 或者里面传 null, run4(null)
如果帮到你, 可以给我赞助杯咖啡☕️
0%