
集合(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前綴就是可變類型?

我們先來看List,List實(shí)現(xiàn)了Collection接口,而MutableList實(shí)現(xiàn)的是List和MutableCollection接口


可以看出,MutableCollection接口實(shí)現(xiàn)了Collection接口,并且在里面添加了add和remove等操作方法,
所以加了Mutable前綴就是可變類型,而沒有的就是不可變類型。
創(chuàng)建集合
Kotlin沒有用于創(chuàng)建列表或集合的專用語法結(jié)構(gòu),只能使用標(biāo)準(zhǔn)庫中的方法: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)
范圍表達(dá)式由rangeTo函數(shù)形成,操作符形式為..,由in和!in進(jìn)行連接,可以用于判斷,也可用于循環(huán)當(dāng)中:
if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
println(i)
}
為什么..能夠替換rangeTo函數(shù),這就涉及到運(yùn)算符的重載了。
運(yùn)算符重載

Kotlin提供了一些運(yùn)算符,這些運(yùn)算符有固定的符號表示形式(如+或-),運(yùn)算符重載要在函數(shù)加operator關(guān)鍵字,在使用直接用運(yùn)算符來替換函數(shù),如..替換rangeTo函數(shù):
if (i in 1..10) {
println(i)
}
// 等同與
if (i in 1.rangeTo(10)) {
println(i)
}
常見運(yùn)算符
如+、%、in、==等等,都是運(yùn)算符重載。
前綴運(yùn)算符

遞增和遞減

算術(shù)運(yùn)算符

in和!in運(yùn)算符

索引訪問操作符

調(diào)用運(yùn)算符

賦值(Augmented assignments)

注意:賦值在 Kotlin 中不是表達(dá)式。
等式運(yùn)算符

注意:===和!==沒有被重載
比較運(yùn)算符
針對Int類型,是去調(diào)用compareTo函數(shù)來比較

范圍(Ranges)
范圍表達(dá)式由rangeTo函數(shù)形成,操作符形式為..,由in和!in進(jìn)行連接,可以用于判斷,也可用于循環(huán)當(dāng)中:
if (i in 1..10) { // i in 1..10 等同于1 <= i && i <= 10
println(i)
}
簡寫
(1..10).forEach { print(it) }
為什么..能夠替換rangeTo函數(shù),這就涉及到運(yùn)算符的重載了。
運(yùn)算符重載

運(yùn)算符重載要在函數(shù)加operator關(guān)鍵字,
Ranges是如何運(yùn)行的
Ranges包含三種IntRange,LongRange,CharRange,都是實(shí)現(xiàn)了通用接口ClosedRange<T>

ClosedRange<T>表示在數(shù)學(xué)意義上的閉區(qū)間,定義為可比較類型,具有兩個端點(diǎn)start和endInclusive,以及包含的范圍,用in和!in來進(jìn)行操作。

Ranges在實(shí)現(xiàn)ClosedRange<T>的同時,也分別繼承了相對應(yīng)的運(yùn)算進(jìn)度類,如IntRange繼承了IntProgression類,由first元素,last元素和不為零的step來定義,第一個元素是first元素,后面的元素是上一個元素加上step的結(jié)果。

Progression進(jìn)度類是Iterable<T>的子類,T包括Int、Long 和 Char三種類型,這就是Ranges可以用于for循環(huán)和map/filter等函數(shù)。

在Progression進(jìn)度類中,有個伴生對象里面的函數(shù)fromClosedRange用來構(gòu)建進(jìn)度。
總結(jié)下,..操作符創(chuàng)建一個實(shí)現(xiàn)了ClosedRange <T>和繼承了*Progression的對象。例如IntRange實(shí)現(xiàn)了ClosedRange <Int>接口,并繼承了IntProgression類,因此為IntProgression里面的所有操作都可用在IntRange。
常用函數(shù)
Ranges的函數(shù)基本都是擴(kuò)展函數(shù)。
rangeTo()

默認(rèn)的rangeTo是正序的,如果將1..10改為10..1的話,上面的循環(huán)是不會執(zhí)行的:
for (i in 10..1) {
println(i) // prints nothing
}
浮點(diǎn)數(shù)(Float和Double)不能使用rangeTo操作,而是使用提供的通用Comparable類型的標(biāo)準(zhǔn)庫:
public operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
該方法不能用于循環(huán)迭代(for循環(huán)等等)。
downTo()

downTo()在是擴(kuò)展函數(shù)的同時,也是中綴函數(shù),使用downTo()函數(shù)控制倒序輸出:
for (i in 10 downTo 1) {
println(i) // 打印10987654321
}
簡寫
(10 downTo 1).forEach { print(it) } // 打印10987654321
step()

step()也是中綴函數(shù),默認(rèn)間隔長度是1,如果要自定義間隔長度的話,就要使用step()函數(shù):
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()也是中綴函數(shù),要創(chuàng)建不包含其終端元素的范圍,可以使用until()函數(shù):
for (i in 1 until 10) { // i in [1, 10), 打印123456789
println(i)
}
簡寫
(1 until 10).forEach { print(it) } // 打印123456789
reversed()

reversed()函數(shù),功能同單詞,反向,由于reversed()并不是中綴函數(shù),所以寫法跟上面的那些不一樣:
for (i in (1..4).reversed())
print(i) // print 4321
簡寫
(1..4).reversed().forEach { print(it) } // print 4321