五、Scala中的数据结构
Scala中的数据结构
文章目录
- 1. 可变集合与不可变集合
- 2. 数组-定长数组(声明泛型)
- 3. 数组-变长数组(声明泛型)
- 4. 定长数组与变长数组的转换
- 5. 多维数组
- 6. 数组-Scala数组与Java的List的互转
- 7. 元组Tuple-元组的基本使用
- 8. 列表 List
- 9. 列表 ListBuffer
- 10. 集合通用符号和方法
- 11. 队列
- 12. 重载运算符
- 13. 映射 Map
- 14. 集 Set
- 15. Set和Map通用符号
- 16. 集合元素的映射-map映射操作
- 17. flatmap映射
- 18. 集合元素的过滤-filter
- 19. 化简 reduce
- 20. 折叠 fold
- 21. 扫描 scan
- 22. 集合应用案例
- 23. 扩展-拉链(合并)
- 24. 扩展-迭代器
- 25. 扩展-流 Stream
- 26. 扩展-视图 View
- 27. 扩展-线程安全的集合
- 28. 扩展-并行集合
- 29. 扩展-操作符
1. 可变集合与不可变集合
-
Scala同时支持不可变集合和可变集合,不可变集合可以安全的并发访问
-
两个主要的包:
- 不可变集合:scala.collection.immutable
- 可变集合: scala.collection.mutable
-
Scala默认采用不可变集合,对于几乎所有的集合类,Scala都同时提供了可变(mutable)和不可变(immutable)的版本
-
Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。在Scala中,集合有可变(mutable)和不可变(immutable)两种类型。
来看一个表
var和val的可变与不可变:指的是声明的变量(mySet)是可不可以改变
- var:它指向的内存地址(即指针)可以变,但是这里跟上面的比喻有些出入,如果对变量重新赋值,就相当于把这个名字给了别人,原来那个人就没有名字了。一段时间后,就会被当成垃圾回收掉
- val:它指向的内存地址(即指针)不可变。即一个人他不可以改名,从生到死都只能用这个名字。
而集合的可变与不可变:指的是对象本身可不可以改变。对象本身是一段内存地址,在scala中我们是不能直接访问的,只能通过mySet这个变量来访问
- 可变对象:它有add,move,clear等方法,它的那一段内存地址存储的内容和大小是可以改变的。
- 不可变对象:它没有add,move,clear等方法,它的那一段内存地址从声明之后就不能改变。【即一个不可变对象,里面所有的内容都不允许改变,和String一个道理】
- 如果将var跟不可变对象结合使用,在使用"+"等连接操作时,实际上是重新创建了一个新的对象,原来的对象已经废弃了。(结合java中String理解)
1 | var mySet=Set("a","b"); //声明一个可变的mySet变量,可以想象mySet指向的内存地址是A0001 |
在scala中集合主要在三个包里面:scala.collection, scala.collection.immutable和scala.collection.mutable。
scala中引入不可变集合是为了方便程序的使用并减少在程序中的未知风险。如果一个集合被定义为不可变的,那么我们在使用的过程中就可以指定该集合是不会变化的,可以放心使用。
scala.collection层次
scala.collection.immutable不可变集合继承层次
- Set、Map是Java中也有的集合,和java中的用法非常相似,但是有一点不同
- Seq是Java没有的,我们发现List归属到Seq了,因此这里的List就和java不是同一个概念了
- 我们前面的for循环如
for( i <- 1 to 3)
,就是IndexedSeq 下的Vector - String也是属于IndexeSeq,其实就是Char的集合
- 我们发现经典的数据结构比如Queue 和 Stack被归属到LinearSeq
- 大家注意Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持排序
- IndexSeq 和 LinearSeq 的区别[IndexSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引
集合,通过索引即可定位],[LineaSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找,它的价值在于应用到一些具体的应用场景]
scala.collection.mutable可变集合继承层次
2. 数组-定长数组(声明泛型)
第一种方式定义数组
这里的数组等同于Java中的数组,中括号的类型就是数组的类型
1 | package dataStructure.arrayPack |
反编译,看重点那几行
1 | public final class T1$ { |
第二种方式定义数组
1 | package dataStructure.arrayPack |
上面代码的反编译
1 | public final class T2$ { |
3. 数组-变长数组(声明泛型)
1 | package dataStructure.arrayPack |
反编译
1 | public final class T3$ { |
另外一个例子
1 | package dataStructure.arrayPack |
再来看一个小例子
1 | val a=new ArrayBuffer[Int](1)//直接new一个对象 |
反编译为:
1 | ArrayBuffer a = new ArrayBuffer(1); |
说明
- ArrayBuffer是变长数组,类似java的ArrayList
val arr2 = ArrayBuffer[Int]()
也是使用的apply方法构建对象def append(elems: A*) { appendAll(elems) }
接收的是可变参数
4)每append一次,arr2在底层会重新分配空间,进行扩容,arr2的内存地址会发生变化,也就成为新的ArrayBuffer
1 | //定义/声明 |
这点类似于java的ArrayList,每append一次,底层会重新分配空间,进行扩容,内存地址会发生变化,也就会成为新的ArrayBuffer
4. 定长数组与变长数组的转换
1 | arr1.toBuffer //定长数组转可变数组 |
说明:
- arr2.toArray 返回结果才是一个定长数组,arr2本身没有变化
- arr1.toBuffer返回结果才是一个可变数组,arr1本身没有变化
1 | val arr2 = ArrayBuffer[Int]() |
5. 多维数组
1 | //定义 |
示例:
1 | val array1 = Array.ofDim[Int](3, 4) |
6. 数组-Scala数组与Java的List的互转
1 | package Test |
7. 元组Tuple-元组的基本使用
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组,最多的特点灵活,对数据没有过多的约束。
注意:元组中最大只能有22个元素
1 | package dataStructure.tuplePack |
上面代码的反编译
1 | public final class T1$ { |
再来看一个案例
1 | //1. 通过apply方法创建元组对象 |
说明
- tuple1 的类型是 Tuple5类 是scala特有的类型
- tuple1 的类型取决于 t1 后面有多少个元素, 有对应关系,比如 4个元素对应 Tuple4
- 给大家看一个Tuple5 类的定义,大家就了然了
1 | final case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5) |
- 元组中最大只能有22个元素 即
Tuple1...Tuple22
元组数据的访问
访问元组中的数据,可以采用顺序号(_顺序号),也可以通过索引(productElement)访问。
1 | val t1 = (1, "a", "b", true, 2) |
元组数据的遍历
1 | val tuple1 = (1, 2, 3, "hello", 4) |
8. 列表 List
Scala中的List 和Java List 不一样,在Java中List是一个接口,真正存放数据是ArrayList,而Scala的List可以直接存放数据,就是一个object,默认情况下Scala的List是不可变的,List属于序列Seq。
List源码的定义
1 | //定义在package object scala,因为Package scala 这个包可以直接用,而scala._ |
List定义在package object scala
,所以Package scala
这个包可以直接使用,而scala._
是Scala语言自动引入的包,所以我们不用再引入任何包,就可以使用List。
创建List
1 | package dataStructure.listPack |
小节
- List默认为不可变的集合
- List 在 scala包对象声明的,因此不需要引入其它包也可以使用
- 源码定义
val List = scala.collection.immutable.List
- List 中可以放任何数据类型,比如 arr1的类型为 List[Any]
- 如果希望得到一个空列表,可以使用Nil对象, 在 scala包对象声明的,因此不需要引入其它包也可以使用
访问List元素
1 | val value1 = list1(1) // 1是索引,表示取出第2个元素. |
List元素的追加
默认scala提供的集合都是不可变的,增加元素都会产生一个新的集合。(和String拼接原理类似)
方式1-在列表的最后增加数据
1 | var list1 = List(1, 2, 3, "abc") |
方式2-在列表的最前面增加数据
1 | var list1 = List(1, 2, 3, "abc") |
方式3- ::
的使用,这个符号应该是List的特有符号
- 符号
::
表示向集合中 新建集合添加元素。 - 运算时,集合对象一定要放置在最右边
- 运算规则,从右向左。
:::
运算符是将集合中的每一个元素加入到空集合中去,即:::
操作的对象时集合,而::
操作的对象是一个个具体的元素值
1 | val list1 = List(1, 2, 3, "abc") |
9. 列表 ListBuffer
ListBuffer是可变的list集合,可以添加,删除元素,ListBuffer属于序列(seq)
添加元素
1 | package dataStructure.arrayPack |
合并两个ListBuffer
1 | val lst0 = ListBuffer(1,2,3) |
更新ListBuffer中元素
1 | val a = ArrayBuffer(1, 2, 3) |
删除ListBuffer中元素
1 | val a = ArrayBuffer(1, 2, 3) |
10. 集合通用符号和方法
可变元素通用符号和方法
1 | 通用方法:append remove |
不可变元素通用符号和方法
1 | 通用方法:无 |
特例:
- 元祖Tuple不能使用()作为下标
::
、:::
是列表List的特殊使用方式,其它的集合不能用
11. 队列
- 队列是一个有序列表,在底层可以用数组或是链表来实现。
- 其输入和输出要遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
- 在Scala中,由设计者直接给我们提供队列类型使用。
- 在scala中, 有
scala.collection.mutable.Queue
和scala.collection.immutable.Queue
, 一般来说,我们在开发中通常使用可变集合中的队列。
创建队列
1 | import scala.collection.mutable |
向队列中追加单个元素和集合
1 | import scala.collection.mutable |
按照队尾进(将数据添加到队列的最后),队头出 来进出队列
1 | import scala.collection.mutable |
也可以有双端队列的用
返回队列的第一个元素
1 | println(q1.head) |
返回队列最后一个元素
1 | println(q1.last) |
返回除了第一个以外剩余的元素, 可以级联使用,这个在递归时使用较多。
1 | println(q1.tail) |
12. 重载运算符
补充一个小知识点
1 | package dataStructure.queuePack |
13. 映射 Map
Java中的Map回顾
HashMap 是一个散列表(数组+链表),它存储的内容是键值对(key-value)映射,Java中的HashMap是无序的,key不能重复。
1 | //只要类型上有<String,Integer>就行,后面的要不要都行 |
Scala中的Map介绍
- Scala中的Map 和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的。
- Scala中,有可变Map (scala.collection.mutable.Map) 和 不可变Map(scala.collection.immutable.Map)
13.1 创建map的四种方式
方式1-构造不可变映射
Scala中的不可变Map是有序,构建Map中的元素底层是Tuple2类型。
1 | val map1 = Map("Alice" -> 10, "Bob" -> 20, "Kotlin" -> "北京")//->为Map的独特写法 |
小结
- 从输出的结果看到,输出顺序和声明顺序一致
- 构建Map集合中,集合中的元素其实是Tuple2类型
- 默认情况下(即没有引入其它包的情况下),Map是不可变map
- 为什么说Map中的元素是Tuple2 类型 [反编译或看对应的apply]
方式2-构造可变映射
1 | //需要指定可变Map的包 |
从输出的结果看到,输出顺序和声明顺序不一致
方式3-创建空的映射
1 | val map3 = new scala.collection.mutable.HashMap[String, Int] |
方式4-对偶元组
即创建包含键值对的二元组, 和第一种方式等价,只是形式上不同而已。
对偶元组 就是只含有两个数据的元组。
1 | import scala.collection.mutable |
13.2 Map-取值
方式1-使用map(key)
1 | val value1 = map2("Alice") |
说明:
- 如果key存在,则返回对应的值
- 如果key不存在,则抛出异常[java.util.NoSuchElementException]
- 在Java中,如果key不存在则返回null
方式2-使用contains方法检查是否存在key
1 | // 返回Boolean |
使用containts先判断在取值,可以防止异常,并加入相应的处理逻辑
1 | val map4 = mutable.Map( ("A", 1), ("B", 2), ("C", 3),("D", 30.9) ) |
方式3-使用map.get(key).get取值
通过 映射.get(键)
这样的调用返回一个Option对象,要么是Some,要么是None
1 | import scala.collection.mutable |
说明和小结:
- map.get方法会将数据进行包装
- 如果 map.get(key) key存在返回some,如果key不存在,则返回None
- 如果 map.get(key).get key存在,返回key对应的值,否则,抛出异常java.util.NoSuchElementException: None.get
方式4-使用map4.getOrElse()取值
getOrElse 方法 : def getOrElse[V1 >: V](key: K, default: => V1)
说明:
- 如果key存在,返回key对应的值。
- 如果key不存在,返回默认值。在java中底层有很多类似的操作。
如何选择取值方式建议
- 如果我们确定map有这个key ,则应当使用map(key), 速度快
- 如果我们不能确定map是否有key ,而且有不同的业务逻辑,使用map.contains() 先判断在加入逻辑
- 如果只是简单的希望得到一个值,使用
map4.getOrElse("ip","127.0.0.1")
1 | import scala.collection.mutable |
13.3 更新map的元素
1 | val map4 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) |
说明:
- map 是可变的,才能修改,否则报错
- 如果key存在:则修改对应的值, key不存在,等价于添加一个key-val
13.4 添加map元素
方式1-增加单个元素
1 | import scala.collection.mutable |
方式2-增加多个元素
1 | import scala.collection.mutable |
13.5 删除map元素
1 | import scala.collection.mutable |
- “A”,“B” 就是要删除的key, 可以写多个.
- 如果key存在,就删除,如果key不存在,也不会报错.
13.6 对map遍历
对map的元素(元组Tuple2对象 )进行遍历的方式很多,具体如下:
1 | import scala.collection.mutable |
说明
1.每遍历一次,返回的元素是Tuple2
2.取出的时候,可以按照元组的方式来取
14. 集 Set
集是不重复元素的结合。集不保留顺序,默认是以哈希集实现
Java中Set的回顾
java中,HashSet是实现Set<E>
接口的一个实体类,数据是以哈希表的形式存放的,里面的不能包含重复数据。Set接口是一种不包含重复元素的 collection,HashSet中的数据也是没有顺序的。
1 | HashSet hs = new HashSet<String>(); |
Scala中Set的说明
默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用scala.collection.mutable.Set
包
集 Set-创建
Set不可变集合的创建
1 | val set = Set(1, 2, 3) //不可变 |
Set可变集合的创建
1 | import scala.collection.mutable |
可变集合的元素添加
1 | mutableSet.add(4) //方式1 |
说明:如果添加的对象已经存在,则不会重复添加,也不会报错
可变集合的元素删除
1 | val set02 = mutable.Set(1,2,4,"abc") |
说明:说明:如果删除的对象不存在,则不生效,也不会报错
集 Set-遍历
1 | val set02 = mutable.Set(1, 2, 4, "abc") |
集 Set-更多操作
15. Set和Map通用符号
+=
即可以添加一个元素,也可以添加一个集合
在Set中
1 | mutableSet.add(4) //方式1 |
在Map中
1 | import scala.collection.mutable |
16. 集合元素的映射-map映射操作
看一个实际需求
要求:请将List(3,5,7) 中的所有元素都 * 2 ,将其结果放到一个新的集合中返回,即返回一个新的List(6,10,14), 请编写程序实现
用传统的方法解决
1 | val list1 = List(3, 5, 7) |
map映射操作
上面提出的问题,其实就是一个关于集合元素映射操作的问题。
在Scala中可以通过map映射操作来解决:将集合中的每一个元素通过指定功能(函数)映射(转换)成新的结果集合这里其实就是所谓的将函数作为参数传递给另外一个函数,这是函数式编程的特点
以HashSet为例说明
def map[B](f: (A) ⇒ B): HashSet[B]
//map函数的签名
- 这个就是map映射函数集合类型都有
[B]
是泛型- map 是一个高阶函数(可以接受一个函数的函数,就是高阶函数),可以接收函数
f: (A) => B
后面详解(先简单介绍下.) HashSet[B]
就是返回的新的集合
使用map映射函数来解决
1 | val list1 = List(3, 5, 7) |
为了进一步理解,我们在举一个高阶函数的案例
1 | def main(args: Array[String]): Unit = { |
高阶函数基本使用
1 | def main(args: Array[String]): Unit = { |
深刻理解map映射函数的机制-模拟实现
1 | package dataStructure.mapPack |
一个练习
请将 val names = List("Alice", "Bob", "Nick")
中的所有单词,全部转成字母大写,返回到新的List集合中
1 | val names = List("Alice", "Bob", "Nick") |
17. flatmap映射
flatmap映射:flat即压扁,压平,扁平化映射
flatmap:flat即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合。
看一个案例:
1 | val names = List("Alice", "Bob", "Nick") |
18. 集合元素的过滤-filter
filter:将符合要求的数据(筛选)放置到新的集合中
应用案例:将 val names = List("Alice", "Bob", "Nick")
集合中首字母为’A’的筛选到新的集合。
1 | val names = List("Alice", "Bob", "Nick") |
19. 化简 reduce
看一个需求:
val list = List(1, 20, 30, 4 ,5) , 求出list的和.
化简:将二元函数引用于集合中的函数。
上面的问题当然可以使用遍历list方法来解决,这里我们使用scala的化简方式来完成
1 | val list = List(1, 20, 30, 4, 5) |
说明
def reduceLeft[B >: A](@deprecatedName('f) op: (B, A) => B): B
- reduceLeft(f) 接收的函数需要的形式为
op: (B, A) => B): B
- reduceleft(f) 的运行规则是 从左边开始执行将得到的结果返回给第一个参数
- 然后继续和下一个元素运行,将得到的结果继续返回给第一个参数,继续和下一个元素运行
- 即:
((((1 + 2) + 3) + 4) + 5) = 15
reduceLefft(_ + _)
这个函数的执行逻辑如图:
reduceRight(_ - _)
反之同理
练习一下
- 分析下面的代码输出什么结果
1 | val list = List(1, 2, 3, 4 ,5) |
- 使用化简的方法求出 List(3,4,2,7,5) 最小的值
1 | val list = List[Int](3,4,2,7,5) |
20. 折叠 fold
fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历。
- 可以把reduceLeft看做简化版的foldLeft。如何理解:
1 | def reduceLeft[B >: A]( ('f) op: (B, A) => B): B = |
大家可以看到,reduceLeft就是调用的foldLeft[B](head)
,并且是默认从集合的head元素开始操作的。
- 相关函数:fold,foldLeft,foldRight,可以参考reduce的相关方法理解
应用案例
1 | // 折叠 |
说明
折叠的原理和化简的运行机制几乎一样,list.foldLeft(5)(minus)
可以理解为
1 | val list = List(5,1,2,3,4) |
list.foldRight(5)(minus)
可以理解为
1 | val list = List(1,2,3,4,5) |
foldLeft和foldRight 缩写方法分别是:/:
和:\
1 | val list4 = List(1, 9, 2, 8) |
21. 扫描 scan
扫描,即对某个集合的所有元素做fold操作,但是会把产生的所有中间结果放置于一个集合中保存
应用实例1
1 | def minus( num1 : Int, num2 : Int ) : Int = { |
说明:
- 把5放在List的第一位,此时List为
(5,1,2,3,4,5)
- 把5放入Vector中,此时Vector(5)
- 执行5-1=4,放入Vector,此时Vector(5,4)
- 执行4-2=2,放入Vector,此时Vector(5,4,2)
- 依次类推,直到执行-5-5=-10,此时 Vector(5, 4, 2, -1, -5, -10)
应用案例2
1 | def minus( num1 : Int, num2 : Int ) : Int = { |
说明
- 把5放在List的最后一位,此时List为
(1,2,3,4,5,5)
- 把5放入Vector中,此时Vector(5)
- 执行5-5=0,使用头插法插入Vertor,此时Vector(0,5)
- 执行4-0=4,使用头插法插入Vertor,此时Vector(4,0,5)
- 执行3-4=-1,使用头插法插入Vertor,此时Vector(-1,4,0,5)
- 依次类推,直到执行1-3=-2,此时 Vector(-2, 3, -1, 4, 0, 5)
22. 集合应用案例
案例1
一个变量sentence
1 | val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD" |
将sentence 中各个字符,通过foldLeft存放到 一个ArrayBuffer中
目的:理解flodLeft的用法.
1 | val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD" |
案例2
一个变量sentence
1 | val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD" |
使用映射集合,统计一句话中,各个字母出现的次数
提示:Map[Char, Int]()
1 | import scala.collection.mutable.Map |
23. 扩展-拉链(合并)
在开发中,当我们需要将两个集合进行 对偶元组合并,可以使用拉链。
1 | // 拉链 |
注意事项
- 拉链的本质就是两个集合的合并操作,合并后每个元素是一个 对偶元组。
- 操作的规则下图:
- 如果两个集合个数不对应,会造成数据丢失。
- 集合不限于List, 也可以是其它集合比如 Array
- 如果要取出合并后的各个对偶元组的数据,可以遍历
1 | for(item<-list3){ |
24. 扩展-迭代器
通过iterator方法从集合获得一个迭代器,通过while循环和for表达式对集合进行遍历(学习使用迭代器来遍历)
1 | val iterator = List(1, 2, 3, 4, 5).iterator // 得到迭代器 |
- iterator 的构建实际是 AbstractIterator 的一个匿名子类,该子类提供了
1 | def iterator: Iterator[A] = new AbstractIterator[A] { |
-
该AbstractIterator 子类提供了 hasNext next 等方法.
-
因此,我们可以使用 while的方式,使用hasNext next 方法变量
25. 扩展-流 Stream
stream是一个集合。这个集合,可以用于存放无穷多个元素,但是这无穷个元素并不会一次性生产出来,而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则(即:要使用结果才进行计算的) 。
案例:
1 | def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1) |
说明
- Stream 集合存放的数据类型是
BigInt
- numsForm 是自定义的一个函数,函数名是程序员指定的。
- 创建的集合的第一个元素是 n , 后续元素生成的规则是 n + 1
- 后续元素生成的规则是可以程序员指定的 ,比如 numsForm( n * 4)…
使用tail,会动态的向stream集合按规则生成新的元素
1 | //创建Stream |
如果使用流集合,就不能使用last属性,如果使用last集合就会进行无限循环
使用map映射stream的元素并进行一些计算
1 | //创建Stream |
26. 扩展-视图 View
Stream的懒加载特性,也可以对其他集合应用view方法来得到类似的效果,具有如下特点:
- view方法产出一个总是被懒执行的集合。
- view不会缓存数据,每次都要重新计算,比如遍历View时。
应用案例
请找到1-100 中,数字倒序排列 和它本身相同的所有数。(1 2, 11, 22, 33 …)
1 | def multiple(num: Int): Int = { |
27. 扩展-线程安全的集合
所有线程安全的集合都是以Synchronized开头的集合
1 | SynchronizedBuffer |
28. 扩展-并行集合
parallel(并行)
- Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
- 主要用到的算法有:
Divide and conquer : 分治算法,Scala通过splitters(分解器),combiners(组合器)等抽象层来实现,主要原理是将计算工作分解很多任务,分发给一些处理器去完成,并将它们处理结果合并返回
Work stealin算法【学数学】,主要用于任务调度负载均衡(load balancing),通俗点完成自己的所有任务之后,发现其他人还有活没干完,主动(或被安排)帮他人一起干,这样达到尽早干完的目的
应用案例
打印1~5
1 | (1 to 5).foreach(println(_)) |
查看并行集合中元素访问的线程
1 | val result1 = (0 to 100).map{case _ => Thread.currentThread.getName} |
29. 扩展-操作符
这部分内容没有必要刻意去理解和记忆,语法使用的多了,自然就会熟练的使用,该部分内容了解一下即可。
操作符扩展
- 如果想在变量名、类名等定义中使用语法关键字(保留字),可以配合反引号反引号
1 | val `val` = 42 |
- 中置操作符:A 操作符 B 等同于 A.操作符(B)
1 | val n1 = 1 |
- 后置操作符:A操作符 等同于
A.操作符
,如果操作符定义的时候不带()则调用时不能加括号
1 | object T9 { |
- 前置操作符,
+、-、!、~
等操作符A等同于A.unary_操作符
1 | object T9 { |
- 赋值操作符,
A 操作符= B
等同于A = A 操作符 B
,比如 A += B 等价 A = A + B