Kotlin學(xué)習(xí)(十三): 集合(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實(shí)現(xiàn)了Collection接口,而MutableList實(shí)現(xiàn)的是List和MutableCollection接口

Collection
MutableCollection

可以看出,MutableCollection接口實(shí)現(xiàn)了Collection接口,并且在里面添加了addremove等操作方法,
所以加了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)算符重載

rangeTo

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)算符重載

rangeTo

運(yùn)算符重載要在函數(shù)加operator關(guān)鍵字,

Ranges是如何運(yùn)行的

Ranges包含三種IntRange,LongRange,CharRange,都是實(shí)現(xiàn)了通用接口ClosedRange<T>

ClosedRange

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

Progression

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

Iterable

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

fromClosedRange

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()

rangeTo

默認(rèn)的rangeTo是正序的,如果將1..10改為10..1的話,上面的循環(huán)是不會執(zhí)行的:

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

浮點(diǎn)數(shù)(FloatDouble)不能使用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

downTo()在是擴(kuò)展函數(shù)的同時,也是中綴函數(shù),使用downTo()函數(shù)控制倒序輸出:

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

簡寫

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

step()

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

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

reversed()函數(shù),功能同單詞,反向,由于reversed()并不是中綴函數(shù),所以寫法跟上面的那些不一樣:

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

簡寫

(1..4).reversed().forEach { print(it) } // print 4321
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容