Kotlin編碼竅門之區(qū)間(Ranges)

區(qū)間表達(dá)式由rangeTo函數(shù)和..操作符輔以in!in構(gòu)成。可以為任意可比較的類型定義區(qū)間拳喻,但是對于整形這種原生類型,區(qū)間的實(shí)現(xiàn)已經(jīng)被優(yōu)化了猪腕。如下是一個使用區(qū)間的例子:

if (i in 1..10) { // equivalent of 1 <= i && i <= 10
    println(i)
}

整形區(qū)間(IntRange, LongRange, CharRange)有一個額外特性:它們可以被迭代冗澈。編譯器負(fù)責(zé)將其轉(zhuǎn)換為類似Java的基于索引的for循環(huán)而無額外開銷。

for (i in 1..4) print(i) // prints "1234"

for (i in 4..1) print(i) // prints nothing

如果你想倒序迭代數(shù)字呢陋葡?也肯簡單亚亲,可以使用標(biāo)準(zhǔn)庫中定義的downTo()函數(shù):

for (i in 4 downTo 1) print(i) // prints "4321"

能否以不為1的任意步長迭代數(shù)字?當(dāng)然可以脖岛,step()函數(shù)可以實(shí)現(xiàn)該功能:

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

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

如果要創(chuàng)建一個不包含結(jié)束元素的區(qū)間朵栖,則可以使用until函數(shù):

for (i in 1 until 10) { // i in [1, 10), 10 is excluded
     println(i)
}

它如何工作(How it works)

區(qū)間實(shí)現(xiàn)了庫中的一個公共接口:ClosedRange<T>

這個ClosedRange<T>是為可比較類型定義的柴梆,在數(shù)學(xué)意義上表示一個閉區(qū)間陨溅。它有兩個端點(diǎn)startendInclusive,并且這兩個端點(diǎn)都被區(qū)間包含绍在。區(qū)間的主要操作是contains门扇,通常使用in!in的形式。

整形數(shù)列(IntProgression, LongProgression, CharProgression)表示一個等差數(shù)列偿渡。數(shù)列由首元素first臼寄、末尾元素last和非0的公差step確定。末尾元素last總會被迭代命中溜宽,除非該數(shù)列是空的吉拳。

數(shù)列是Iterable<N>的子類型,其中N可以是Int适揉,LongChar留攒,因此數(shù)列可以被用于for循環(huán)和像map煤惩,filter等函數(shù)中。數(shù)列的迭代相當(dāng)于Java/JavaScript中的基于索引的for循環(huán):

for (int i = first; i != last; i += step) {
  // ...
}

對于整數(shù)類型炼邀,..操作符創(chuàng)建了一個同時實(shí)現(xiàn)ClosedRange<T>*Progression的對象魄揉。例如,IntRange實(shí)現(xiàn)了ClosedRange<Int>接口拭宁,且繼承自IntProgression洛退,因此IntRange可以使用所有定義在IntProgression中的操作。downTo()step()函數(shù)的結(jié)果總是一個*Progression杰标。

數(shù)列由在其伴生對象中定義的fromClosedRange函數(shù)構(gòu)造:

IntProgression.fromClosedRange(start, end, step)

數(shù)列的last元素的計算方法是:若step是正數(shù)兵怯,則計算不大于end值的最大值;若step是負(fù)數(shù)在旱,則計算不小于end值的最小值摇零;且最大值和最小值需要滿足:(last - first) % step == 0

使用函數(shù)(Utility functions)

rangeTo()

整形類型的rangeTo()操作符只是調(diào)用*Range類的構(gòu)造器,如:

class Int {
    //...
    operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
    //...
    operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
    //...
}

浮點(diǎn)數(shù)(Double,Float)沒有定義rangeTo操作符桶蝎,但是由標(biāo)準(zhǔn)庫提供了一個支持泛型的Comparable來代替:

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

由此函數(shù)返回的區(qū)間不能用于迭代驻仅。

downTo()

擴(kuò)展函數(shù)downTo()是為整數(shù)類型定義的,這有兩個例子:

fun Long.downTo(other: Int): LongProgression {
    return LongProgression.fromClosedRange(this, other.toLong(), -1L)
}

fun Byte.downTo(other: Int): IntProgression {
    return IntProgression.fromClosedRange(this.toInt(), other, -1)
}

reversed()

擴(kuò)展函數(shù)reversed()是為每一個*Progression定義的登渣,用于返回一個倒序序列:

fun IntProgression.reversed(): IntProgression {
    return IntProgression.fromClosedRange(last, first, -step)
}

step()

擴(kuò)展函數(shù)step()是為每一個*Progression定義的噪服,返回的數(shù)列的步進(jìn)值(該函數(shù)的參數(shù))已經(jīng)被修改。步進(jìn)值要求總是正的胜茧,因此該函數(shù)不會改變迭代的方向:

fun IntProgression.step(step: Int): IntProgression {
    if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
    return IntProgression.fromClosedRange(first, last, if (this.step > 0) step else -step)
}

fun CharProgression.step(step: Int): CharProgression {
    if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
    return CharProgression.fromClosedRange(first, last, if (this.step > 0) step else -step)
}

注意:為了保證(last - first) % step == 0的成立粘优,該函數(shù)返回的數(shù)列的末尾值可能與原數(shù)列的末尾值不同,例子如下:

(1..12 step 2).last == 11  // progression with values [1, 3, 5, 7, 9, 11]
(1..12 step 3).last == 10  // progression with values [1, 4, 7, 10]
(1..12 step 4).last == 9   // progression with values [1, 5, 9]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呻顽,一起剝皮案震驚了整個濱河市雹顺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌廊遍,老刑警劉巖嬉愧,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喉前,居然都是意外死亡没酣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門卵迂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裕便,“玉大人,你說我怎么就攤上這事见咒〕ニィ” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長下翎。 經(jīng)常有香客問我囱嫩,道長,這世上最難降的妖魔是什么漏设? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮今妄,結(jié)果婚禮上郑口,老公的妹妹穿的比我還像新娘。我一直安慰自己盾鳞,他們只是感情好犬性,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腾仅,像睡著了一般乒裆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上推励,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天鹤耍,我揣著相機(jī)與錄音,去河邊找鬼验辞。 笑死稿黄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的跌造。 我是一名探鬼主播杆怕,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼壳贪!你這毒婦竟也來了陵珍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤违施,失蹤者是張志新(化名)和其女友劉穎互纯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體醉拓,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伟姐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亿卤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愤兵。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖排吴,靈堂內(nèi)的尸體忽然破棺而出秆乳,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布屹堰,位于F島的核電站肛冶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扯键。R本人自食惡果不足惜睦袖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荣刑。 院中可真熱鬧馅笙,春花似錦、人聲如沸厉亏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爱只。三九已至皿淋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恬试,已是汗流浹背窝趣。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留训柴,地道東北人高帖。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像畦粮,于是被迫代替她去往敵國和親散址。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容