Scala-语法

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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
package story.jjw

import java.io.IOException

import scala.beans.BeanProperty
import scala.collection.mutable.ArrayBuffer
import scala.util.control.Breaks

/**
* 除了自己实现main方法之外,还可以继承App Trait,然后将需要在main方法中运行的代码,直接作为object的constructor代码;而且用args可以接受传入的参数
*
* App Trait的工作原理为:App Trait继承自DelayedInit Trait,scalac命令进行编译时,会把继承App Trait的object的constructor代码都放到DelayedInit Trait的delayedInit方法中执行
*/
object HelloWorld extends App {

if (args.length > 0) {
println("hello, " + args(0))
} else {
println("Hello World!!!")
}

}


object One {

/**
* 就如同java中,如果要运行一个程序,必须编写一个包含main方法类一样;在scala中,如果要运行一个应用程序,那么必须有一个main方法,作为入口
* scala中的main方法定义为def main(args: Array[String]),而且必须定义在object中
*/
def main(args: Array[String]): Unit = {
// 1. while循环
var n = 10
while (n > 0) {
println(n)
n = n - 1
}

// 2.for循环
val n1 = 10
for (i <- 0 to n1) {
println("n1.." + i)
}

// 3.for循环遍历字符串
val n2 = "Hello World"
for (i <- n2) {
println(i)
}

// 4.跳出循环语句,scala没有提供类似于java的break语句,使用Breaks提供的函数实现
Breaks.breakable {
var n = 10
for (i <- "Hello World") {
if (n == 5) {
Breaks.break
}
println(i)
n -= 1
}
}

// 5.多重for循环
for (i <- 1 to 9; j <- 1 to 9) {
if (j == 9) {
println(i * j)
} else {
print(i * j + " ")
}
}

// 6.if守卫,取偶数
for (i <- 0 to 9 if i % 2 == 0) {
println(i)
}

// 7.for推导式:构造集合
val vector = for (i <- -1 to 9) yield i
println(vector)

// 8.函数示例
println(sayHello("JJW", 27))

// 9.函数调用默认参数示例
println(sayHello("SS"))

// 10.斐波那契数列
println(fab(9))

// 11.变长参数
println(sum(1, 2, 3, 4, 5))

// 12.使用序列调用变长参数
println(sum(1 to 5: _*))

// 13.lazy值,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算
val valueA = {
println("开始初始化valueA");
1 + 1
}
lazy val valueB = {
println("开始初始化valueB");
1 + 1
}
println(valueA)
println(valueB)

// 14.异常捕获
exceptionProcess(new IOException("IO 异常"))

// 15.Array 和 ArrayBuffer
val arrA = new Array[Int](10)
arrA(0) = 10
println(arrA(0))

val arrB = Array("hello", "world")
println(arrB(1))

val ab = ArrayBuffer[Int]()
ab += 10
ab += (11, 12)
ab ++= Array(13, 14)
println(ab)
ab.trimEnd(3) // 从头截取指定个元素
println(ab)

// 指定索引位置插入元素
ab.insert(0, 15)
ab.insertAll(2, Array(7, 8, 9))
println(ab)

// 删除指定位置元素
ab.remove(1)
ab.remove(1, 3)

// Array 与 ArrayBuffer 相互转换
println(arrB.toBuffer)
println(ab.toArray)

// 普通遍历
for (i <- 0 until arrA.length) {
println(arrA(i))
}

// 跳跃遍历
for (i <- 0 until(ab.length, 2)) {
println(ab(i))
}

// 增强for
for (e <- ab) {
println(e)
}

// 数组一些api
println(ab.sum)
println(ab.max)
scala.util.Sorting.quickSort(arrA)
println(ab.mkString(", "))
println(ab.mkString("(", ", ", ")"))

// 使用yield和函数式编程转换数组
// val arrC = Array(1, 2, 3, 4, 5)
val arrC = ArrayBuffer(1, 2, 3, 4, 5)
val arrD = for (ele <- arrC) yield {
ele * 3
}
println(arrD)

val arrE = arrC.filter(_ % 2 == 1).map(_ * 3)
val arrF = arrC.filter {
_ % 2 == 0
}.map {
_ * 2
}
println("arrE " + arrE)
println("arrF " + arrF)

// 16.Map和Tuple
// 创建不可变Map
val mapA = Map("JJW" -> 20, "SS" -> 20) // mapA("JJW") = 18 map不可变,报错
val mapB = Map(("Leo", 30), ("Jen", 25), ("Jack", 23))

// 创建可变Map
val mapC = scala.collection.mutable.Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
mapC("JJW") = 18
println(mapC)
// Map取值
val age = mapC("JJW")
val leoAge = if (mapC.contains("leo")) mapC("leo") else 0
val jenAge = mapC.getOrElse("Jen", 0) // 上述简化
// 更新元素
mapC("JJW") = 20

// 增加多个元素, 不可变Map元素不可变,不可修改和添加元素,但是可以通过操作得到新的Map
mapC += ("Mike" -> 35, "Tom" -> 40)
// 移除元素
mapC -= "Mike"
// 更新不可变的map
val mapD = mapB + ("Mike" -> 36, "Tom" -> 40)
// 移除不可变map的元素
val mapE = mapB - "Jack"
println(mapC)
println(mapB)
println(mapD)
println(mapE)

// 创建空的HashMap
val hashMap = new scala.collection.mutable.HashMap[String, String]

// 遍历Map
// 普通遍历
for ((key, value) <- mapD) {
println(key + " " + value)
}
// 遍历map的key
for (key <- mapD.keySet) {
println(key)
}
// 遍历map的value
for (value <- mapD.values) {
println(value)
}
// 生成新map,反转key和value
val mapF = for ((key, value) <- mapD) yield {
(value, key)
}
println(mapF)

// SortedMap 和 LinkedHashMap
// SortedMap可以自动对Map的key的排序
val sortedMap = scala.collection.immutable.SortedMap(20 -> "JJW", 10 -> "SS", 30 -> "DD")
println(sortedMap)

// LinkedHashMap是有序的,根据插入数据的顺序
val linkedHashMap = new scala.collection.mutable.LinkedHashMap[String, Int]
linkedHashMap("leo") = 30
linkedHashMap("alice") = 15
linkedHashMap("jen") = 25
println(linkedHashMap)

// Tuple
// 创建
val tuple2 = ("JJW", 20)
// 访问Tuple
tuple2._1
tuple2._2

// zip操作
val names = Array("leo", "jack", "mike")
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) {
println(name + ": " + age)
}

// 17.类
// 创建类的对象,并调用其方法
val helloWorld = new HelloWorld
helloWorld.sayHello()
// 也可以不加括号,如果定义方法时不带括号,则调用方法时也不能带括号
print(helloWorld.getName)

// 使用scala自己生成的get set方法
helloWorld.age = 27
println(helloWorld.age)

// val修饰的,只生成get方法
println(helloWorld.gender)

// 自定义get set方法
helloWorld.myHobby = "玩"
println(helloWorld.myHobby)

// java式的 get set
helloWorld.stature = "178"
println(helloWorld.stature)
helloWorld.setStature("180")
println(helloWorld.stature)

// Java式的构造函数
val s1 = new Student("JJW")
val s2 = new Student("JJW", 20)

// 主constructor创建对象
val t = new Teacher("JJW", "学习", 27)

// object定义的类会在第一次使用的时候初始化构造函数,下载再使用的时候构造函数中的内容不会执行
// println(Person.getEyeNum)
println("++++++++++")
val p = Person

new Person("JJW", 20).sayHello
// 使用object class 类的 apply构造伴生对象(此方法很重要,多处都是这样用的)
Person("SS", 18).sayHello

// 抽象类实例化
val pc: PersonC = new StudentC("JJW")
pc.sayHello

// 18.枚举
println(Season(0))
println(Season.withName("summer"))
for (ele <- Season.values) println(ele)

// 19.类型判断
// isInstanceOf和asInstanceOf
// 需要使用isInstanceOf判断对象是否是指定类的对象,如果是的话,则可以使用asInstanceOf将对象转换为指定类型
val pa: PersonA = new StudentA
var sa: StudentA = null
// 判断类型
if (pa.isInstanceOf[StudentA]) {
// 转换类型
sa = pa.asInstanceOf[StudentA]
}
println(sa)

// getClass和classOf
// isInstanceOf只能判断出对象是否是指定类以及其子类的对象,而不能精确判断出,对象就是指定类的对象
// 如果要求精确地判断对象就是指定类的对象,那么就只能使用getClass和classOf了
println(pa.getClass == classOf[PersonA]) // false
println(pa.getClass == classOf[StudentA]) // true

// 模式匹配判断,isInstanceOf 式的判断,并不是精确判断,既如果是子类依然会匹配成功
pa match {
case per: PersonA => println("it's PersonA's object")
case _ => println("unknown type")
}

val pd = new PersonD("PZ", "好好学习")
pd.eyeNum = 0
pd.sayHello("BQ")

// 创建类的对象时,指定该对象混入某个trait
val pdd = new PersonD("PZ", "好好学习") with MyLogger
pdd.myLog("为实例混入trait")

// trait一个接口,多个实现,一个类又继承了此多个实现,然后我们调用接口的一个方法,这样会从右到左依次执行每个实现中的这个方法
// 重点:责任链模式
val pe = new PersonE("JJW")
pe.sayHello

}

def sayHello(name: String, age: Int = 20) = {
if (age > 18) {
printf("你好, %s, 你成年了: %s \n", name, age)
} else {
printf("你好, %s, 你未成年: %s \n", name, age)
}
age
}

def fab(n: Int): Int = {
if (n <= 1) {
1
} else {
fab(n - 1) + fab(n - 2)
}
}

def sum(nums: Int*): Int = {
var res = 0
for (num <- nums) {
res += num
}
res
}

def sum2(nums: Int*): Int = {
if (nums.length == 0) {
0
} else {
nums.head + sum2(nums.tail: _*)
}
}

def exceptionProcess(err: Exception): Unit = {
try {
throw err
} catch {
case e1: IllegalArgumentException => println("illegal argument")
case e2: IOException => println("io exception")
}
}

}

/**
* 定义类
*/
class HelloWorld {

// 如果不希望生成setter和getter方法,则将field声明为private[this]

// 定义不带private的var field,JVM会提供public的getter和setter方法
var age = 20;

// 而如果使用private修饰field,则生成的getter和setter也是private的
private var name = "leo"

// 如果定义val field,则只会生成getter方法
val gender = "男"

// 由于field是private的,所以setter和getter都是private,对外界没有暴露;自己可以实现修改field值的方法;自己可以覆盖getter方法
private var hobby = "学习"

// Scala的getter和setter方法的命名与java是不同的,是field和field_=的方式
// 如果要让scala自动生成java风格的getter和setter方法,只要给field添加@BeanProperty注解即可
// 此时会生成4个方法,stature: String、stature_=(newValue: String): Unit、getStature(): String、setStature(newValue: String): Unit
@BeanProperty var stature: String = _

def myHobby = hobby

def myHobby_=(newValue: String) {
print("自定义set方法")
hobby = newValue
}

def sayHello() {
println("Hello, " + name)
}

def getName = name

}

class Student {

private var name = ""
private var age = 0

def this(name: String) {
this()
this.name = name
}

def this(name: String, age: Int) {
this(name)
this.age = age
}

}

// 主constructor中还可以通过使用默认参数,来给参数默认的值
// 如果主constrcutor传入的参数什么修饰都没有,比如name: String,那么如果类内部的方法使用到了,则会声明为private[this] name;否则没有该field,就只能被constructor代码使用而已
class Teacher(val name: String, gender: String, val age: Int = 30) {
println("your name is " + name + ", your age is " + age + ", gender is " + gender)
}

/**
* 内部类示例
*/
class Class {

class Student(val name: String)

val students = new ArrayBuffer[Student]

def getStudent(name: String) = {
new Student(name)
}

}

/**
* object,相当于class的单个实例,通常在里面放一些静态的field或者method
* 第一次调用object的方法时,就会执行object的constructor,也就是object内部不在method中的代码;但是object不能定义接受参数的constructor
* 注意,object的constructor只会在其第一次被调用时执行一次,以后再次调用就不会再次执行constructor了
* object通常用于作为单例模式的实现,或者放class的静态成员,比如工具方法
*/
object Person {

private var eyeNum = 2

/**
* 通常在伴生对象中实现apply方法,并在其中实现构造伴生类的对象的功能
* 而创建伴生类的对象时,通常不会使用new Class的方式,而是使用Class()的方式,隐式地调用伴生对象得apply方法,这样会让对象创建更加简洁
*/
def apply(name: String, age: Int) = new Person(name, age)

println("this Person object!")

// def getEyeNum = eyeNum

}

/**
* 伴生对象
*
* 如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
* 伴生类和伴生对象必须存放在一个.scala文件之中
* /伴生类和伴生对象,最大的特点就在于,互相可以访问private field
*/
class Person(val name: String, val age: Int) {
def sayHello = println("Hi, " + name + ", I guess you are " + age + " years old!" + ", and usually you must have " + Person.eyeNum + " eyes.")
}

/**
* object继承类示例
*
* @param message
*/
abstract class Hello(var message: String) {
def sayHello(name: String): Unit
}

object HelloImpl extends Hello("hello") {
override def sayHello(name: String) = {
println(message + ", " + name)
}
}

/**
* scala枚举
*/
object Season extends Enumeration {
val SPRING = Value(0, "spring")
val SUMMER = Value(1, "summer")
val AUTUMN = Value(2, "autumn")
val WINTER = Value(3, "winter")
}

/**
* Scala中,让子类继承父类,与Java一样,也是使用extends关键字
* 继承就代表,子类可以从父类继承父类的field和method;然后子类可以在自己内部放入父类所没有,子类特有的field和method;使用继承可以有效复用代码
* 子类可以覆盖父类的field和method;但是如果父类用final修饰,field和method用final修饰,则该类是无法被继承的,field和method是无法被覆盖的
*/
class PersonA {
private var name = "leo"
val age: Int = 20
def getName = name
}

class StudentA extends PersonA {
private var score = "A"
def getScore = score

// 重写父类 filed
override val age: Int = 27

// 重写父类getName方法
override def getName = "Hi, I'm " + super.getName
}

/**
* 通过子类的主构造函数来调用父类的构造函数(与 Kotlin 一样)
* 注意!如果是父类中接收的参数,比如name和age,子类中接收时,就不要用任何val或var来修饰了,否则会认为是子类要覆盖父类的field
*/
class PersonB(val name: String, val age: Int)
class StudentB(name: String, age: Int, var score: Double) extends PersonB(name, age) {
def this(name: String) {
this(name, 0, 0)
}
def this(age: Int) {
this("leo", age, 0)
}
}

/**
* 子类必须覆盖field,以定义自己的具体field,并且覆盖抽象field,不需要使用override关键字
*
* 而一个类中如果有一个抽象方法,那么类就必须用abstract来声明为抽象类,此时抽象类是不可以实例化的,在子类中覆盖抽象类的抽象方法时,不需要使用override关键字
*
* 与 Kotlin 一样
*/
abstract class PersonC(val name: String) {
val age: Int
def sayHello: Unit
}
class StudentC(name: String) extends PersonC(name) {
val age: Int = 20
def sayHello: Unit = println("Hello, " + name)
}

/**
* 在Scala中,trait是没有接收参数的构造函数的,这是trait与class的唯一区别
*
* Scala中的Triat是一种特殊的概念
* 首先我们可以将Trait作为接口来使用,此时的Triat就与Java中的接口非常类似,在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
* 类可以使用extends关键字继承trait,注意,这里不是implement,在scala中没有implement的概念,无论继承类还是trait,统一都是extends
* 类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
* scala不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可
*
* Scala中的Triat可以不是只定义抽象方法,还可以定义具体方法
*
* Scala中的Triat可以定义具体field,此时继承trait的类就自动获得了trait中定义的field
* 但是这种获取field的方式与继承class是不同的:如果是继承class获取的field,实际是定义在父类中的;而继承trait获取的field,就直接被添加到了类中
*
* Scala中的Triat可以定义抽象field,而trait中的具体方法则可以基于抽象field来编写
* 但是继承trait的类,则必须覆盖抽象field,提供具体的值
*
* 有时我们可以在创建类的对象时,指定该对象混入某个trait,这样,就只有这个对象混入该trait的方法,而类的其他对象则没有
*
* 在Scala中,trait也是有构造代码的,也就是trait中的,不包含在任何方法中的代码
* 而继承了trait的类的构造机制如下:1、父类的构造函数执行;2、trait的构造代码执行,多个trait从左到右依次执行;3、构造trait时会先构造父trait,如果多个trait继承同一个父trait,则父trait只会构造一次;4、所有trait构造完毕之后,子类的构造函数执行
*
* 重点:在Scala中,trait也可以继承自class,此时这个class就会成为所有继承该trait的类的父类(trait不能直接实例化,跟接口一样)
*/
trait Hellotrait {

// 定义具体field
var eyeNum: Int = 2

// 定义抽象字段
val msg: String

// 定义抽象方法
def sayHello(name: String)

// 定义具体方法(类似于Java8 中接口有默认实现一样)
def log(message: String) = println(message)
}

trait MakeFriendsTrait {
def makeFriends(name: String)
}

trait MyLogger{
def myLog(msg: String) {
println("log: " + msg)
}
}

class PersonD(val name: String, override val msg: String) extends Hellotrait with MakeFriendsTrait with Serializable {

override def sayHello(name: String): Unit = {
println("Hello " + name + " I have " + eyeNum + " eyes; " + msg)
}

override def makeFriends(name: String): Unit = {
println("Hello friend " + name)
log("log" + name)
}

}

/**
* Scala中支持让类继承多个trait后,依次调用多个trait中的同一个方法,只要让多个trait的同一个方法中,在最后都执行super.方法即可
* 类中调用多个trait中都有的这个方法时,首先会从最右边的trait的方法开始执行,然后依次往左执行,形成一个调用链条
* 这种特性非常强大,其实就相当于设计模式中的责任链模式的一种具体实现依赖
*
* 注意:要实现责任链这种模式,每种实现中必须要调用 super.(抽象函数)
*/
trait Handler {
def handle(data: String) {}
}
trait DataValidHandler extends Handler {
override def handle(data: String) {
println("check data: " + data)
super.handle(data)
}
}
trait SignatureValidHandler extends Handler {
override def handle(data: String) {
println("check signature: " + data)
super.handle(data)
}
}
class PersonE(val name: String) extends SignatureValidHandler with DataValidHandler {
def sayHello = { println("Hello, " + name); handle(name) }
}

最后更新: 2020年08月06日 15:27

原始链接: https://jjw-story.github.io/2020/08/06/Scala-语法/

× 请我吃糖~
打赏二维码