Kotlin学习(十三): 集合(Collections)和范围(Ranges)

Kotlin

集合(Collections)

Kotlin的集合类型和Java不一样,Kotlin的集合分为可变(读写)和不可变(只读)类型(lists, sets, maps, etc),可变类型是在不可变类型前面加Mutable

  • List<out E>MutableList<E>
  • Set<out E>MutableSet<E>
  • Map<K, out V>MutableMap<K, V>

举个栗子:

val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = numbers
println(numbers)        // prints "[1, 2, 3]"
numbers.add(4)
println(readOnlyView)   // prints "[1, 2, 3, 4]"
// readOnlyView.clear()    // 报错

val strings = hashSetOf("a", "b", "c", "c")
assert(strings.size == 3)

为什么加了Mutable前缀就是可变类型?

Collections

我们先来看List,List实现了Collection接口,而MutableList实现的是List和MutableCollection接口

Collection
MutableCollection

可以看出,MutableCollection接口实现了Collection接口,并且在里面添加了addremove等操作方法,
所以加了Mutable前缀就是可变类型,而没有的就是不可变类型。

创建集合

Kotlin没有用于创建列表或集合的专用语法结构,只能使用标准库中的方法:listOf(), mutableListOf(), setOf(), mutableSetOf(),mapOf()等等。

// 等同于Java的List<String> list = new ArrayList();
val list: List<String> = arrayListOf()
val mutableList: MutableList<String> = mutableListOf()
// 也可以这样写
val list2 = mutableListOf<String>()
val mutableList2 = mutableListOf<String>()

// 等同于Java的Map<String, String> map = new HashMap();
val map: Map<String, String> = mapOf()
val mutableMap: MutableMap<String, String> = mutableMapOf()
// 也可以这样写
val map2 = mapOf<String, String>()
val mutableMap2 = mutableMapOf<String, String>()

其中mapOf()可以简写成mapOf(a to b, c to d)

val map: Map<Int, Int> = mapOf(1 to 1, 2 to 2)

范围(Ranges)

范围表达式由rangeTo函数形成,操作符形式为..,由in!in进行连接,可以用于判断,也可用于循环当中:

if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
    println(i) 
}

为什么..能够替换rangeTo函数,这就涉及到运算符的重载了。

运算符重载

rangeTo

Kotlin提供了一些运算符,这些运算符有固定的符号表示形式(如+-),运算符重载要在函数加operator关键字,在使用直接用运算符来替换函数,如..替换rangeTo函数:

if (i in 1..10) { 
    println(i) 
}
// 等同与
if (i in 1.rangeTo(10)) {
    println(i) 
}

常见运算符

+%in==等等,都是运算符重载。

前缀运算符
递增和递减
算术运算符
in!in运算符
索引访问操作符
调用运算符
赋值(Augmented assignments)

注意:赋值在 Kotlin 中不是表达式。

等式运算符

注意:===!==没有被重载

比较运算符

针对Int类型,是去调用compareTo函数来比较

范围(Ranges)

范围表达式由rangeTo函数形成,操作符形式为..,由in!in进行连接,可以用于判断,也可用于循环当中:

if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
    println(i) 
}

简写

(1..10).forEach { print(it) }

为什么..能够替换rangeTo函数,这就涉及到运算符的重载了。

运算符重载

rangeTo

运算符重载要在函数加operator关键字,

Ranges是如何运行的

Ranges包含三种IntRangeLongRangeCharRange,都是实现了通用接口ClosedRange<T>

ClosedRange

ClosedRange<T>表示在数学意义上的闭区间,定义为可比较类型,具有两个端点startendInclusive,以及包含的范围,用in!in来进行操作。

Progression

Ranges在实现ClosedRange<T>的同时,也分别继承了相对应的运算进度类,如IntRange继承了IntProgression类,由first元素,last元素和不为零的step来定义,第一个元素是first元素,后面的元素是上一个元素加上step的结果。

Iterable

Progression进度类是Iterable<T>的子类,T包括IntLongChar三种类型,这就是Ranges可以用于for循环和map/filter等函数。

fromClosedRange

Progression进度类中,有个伴生对象里面的函数fromClosedRange用来构建进度。

总结下,..操作符创建一个实现了ClosedRange <T>和继承了*Progression的对象。例如IntRange实现了ClosedRange <Int>接口,并继承了IntProgression类,因此为IntProgression里面的所有操作都可用在IntRange

常用函数

Ranges的函数基本都是扩展函数。

rangeTo()

rangeTo

默认的rangeTo是正序的,如果将1..10改为10..1的话,上面的循环是不会执行的:

for (i in 10..1) {
     println(i) // prints nothing
}

浮点数(FloatDouble)不能使用rangeTo操作,而是使用提供的通用Comparable类型的标准库:

public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>

该方法不能用于循环迭代(for循环等等)。

downTo()

downTo

downTo()在是扩展函数的同时,也是中缀函数,使用downTo()函数控制倒序输出:

for (i in 10 downTo 1) {
     println(i) // 打印10987654321
}

简写

(10 downTo 1).forEach { print(it) } // 打印10987654321

step()

step

step()也是中缀函数,默认间隔长度是1,如果要自定义间隔长度的话,就要使用step()函数:

for (i in 1..4 step 2) print(i) // 打印"13"

for (i in 4 downTo 1 step 2) print(i) // 打印"42"

简写

(1..4 step 2).forEach { print(it) } // 打印"13"
(4 downTo 1 step 2).forEach { print(it) } // 打印"42"

until()

until

until()也是中缀函数,要创建不包含其终端元素的范围,可以使用until()函数:

for (i in 1 until 10) { // i in [1, 10), 打印123456789
     println(i)
}

简写

(1 until 10).forEach { print(it) } // 打印123456789

reversed()

reversed

reversed()函数,功能同单词,反向,由于reversed()并不是中缀函数,所以写法跟上面的那些不一样:

for (i in (1..4).reversed())
     print(i) // print 4321

简写

(1..4).reversed().forEach { print(it) } // print 4321
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 80,410评论 1 176
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 27,702评论 1 144
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 32,089评论 0 104
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 17,411评论 0 90
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 22,698评论 0 145
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 18,665评论 1 87
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 11,409评论 2 164
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 10,792评论 0 79
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 9,351评论 5 114
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 12,591评论 0 130
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 11,343评论 1 127
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 12,187评论 0 131
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 6,974评论 0 18
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 9,769评论 2 119
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 12,946评论 3 127
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 8,594评论 0 3
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 8,807评论 0 78
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 13,464评论 2 137
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 14,007评论 2 132

推荐阅读更多精彩内容