Kotlin學習(二):常用關鍵字

  1. by 委托模式

Kotlin中跨晴,委托的實現(xiàn)依靠于關鍵字 by 费封,by表示將抽象主題的實例(by后邊的實例)保存在代理類實例的內(nèi)部,比如SportsManager類繼承于ISports接口,并可以ISports接口的所有的 public 方法委托給一個指定的對象末患。
類委托:

interface ISports {
    fun doSports()
}

class SwimForSports: ISports{
    override fun doSports() {
        println("do swim")
    }
}

class SportsManager(sport: ISports): ISports by sport

fun main(args: Array<String>) {
    val swimSports: SwimForSports = SwimForSports()
    SportsManager(swimSports).doSports()// Log:do swim
}

在SportsManager聲明中,by子句表示,將sport保存在SportsManager的對象實例內(nèi)部隧膏,而且編譯器將會生成繼承自 ISports 接口的所有方法, 并將調(diào)用轉(zhuǎn)發(fā)給sport。

委托屬性:
所謂的委托屬性魏宽,就是對其屬性值的操作不再依賴于其自身的getter()/setter()方法曲稼,是將其托付給一個代理類湖员,從而每個使用類中的該屬性可以通過代理類統(tǒng)一管理贫悄,再也不用在每個類中,對其聲明重復的操作方法娘摔。
當我們使用屬性的get或者set的時候窄坦,屬性委托的getValue和setValue就會被調(diào)用。

fun main(args: Array<String>) {
    val bigHeadSon = BigHeadSon()

    bigHeadSon.money = 100//收到100塊壓歲錢

    println(bigHeadSon.money)//50 被代保管了一半

}

class BigHeadSon {
    var money: Int by Mother()
}

class Mother {

    var moneySon = 0
    var moneyMother = 0

    operator fun getValue(bigHeadSon: BigHeadSon, property: KProperty<*>): Int {
        return moneySon
    }

    operator fun setValue(bigHeadSon: BigHeadSon, property: KProperty<*>, i: Int) {
        moneySon = i / 2
        moneyMother = i / 2
    }
}

延遲加載(Lazy)
lazy()是一個函數(shù), 接受一個Lambda表達式作為參數(shù), 返回一個Lazy類型的實例,這個實例可以作為一個委托, 實現(xiàn)延遲加載屬性(lazy property): 第一次調(diào)用 get() 時, 將會執(zhí)行 lazy() 函數(shù)受到的Lambda 表達式,然后會記住這次執(zhí)行的結(jié)果, 以后所有對 get() 的調(diào)用都只會簡單地返回以前記住的結(jié)果.

惰性加載
by lazy 放到成員變量中凳寺,可以單獨存在
by lazy 返回值就是最后一行
by lazy 是線程安全的

fun main(args: Array<String>) {
    val lazy = Lazy()
    println(lazy.name)
    println(lazy.name)
    println(lazy.name)
}

class Lazy {
    val name: String by lazy {
        println("只初始化一次")
        "懶加載"
    }
}

  1. it Lambda語法

it 來使用此參數(shù)鸭津。it可表示為單個參數(shù)的隱式名稱逆趋,是Kotlin語言約定的魄眉。

 // 即it不是`Kotlin`中的關鍵字冀值【盥可用于變量名稱
val it : Int = 0 

//在 Lambdas 表達式中,大括號與表達式間要有空格焰扳,箭頭與參數(shù)和函數(shù)體間要有空格
list.filter { it > 10 }.map { element -> element * 2 }

在短的且不嵌套的Lambdas中倦零,建議使用it替換參數(shù),有嵌套而已有多個參數(shù)的Lambdas中吨悍,就不能用it來替換參數(shù)扫茅,必須明確聲明參數(shù)。

  1. Kotlin中l(wèi)et, apply, run, with, also函數(shù)

1, 『let』操作符:如果對象的值不為空育瓜,則允許執(zhí)行這個方法葫隙。
場景一: 最常用的場景就是使用let函數(shù)處理需要針對一個可null的對象統(tǒng)一做判空處理。

//判斷object為null的操作
object?.let{//表示object不為null的條件下躏仇,才會去執(zhí)行l(wèi)et函數(shù)體
it.todo()
}

場景二: 然后就是需要去明確一個變量所處特定的作用域范圍內(nèi)可以使用

另一種用途  let函數(shù)的使用的一般結(jié)構(gòu)
object.let{
it.todo()//在函數(shù)體內(nèi)使用it替代object對象去訪問其公有的屬性和方法
...
}

從源碼let函數(shù)的結(jié)構(gòu)來看它是只有一個lambda函數(shù)塊block作為參數(shù)的函數(shù),調(diào)用T類型對象的let函數(shù)恋脚,則該對象為函數(shù)的參數(shù)。在函數(shù)塊內(nèi)可以通過 it 指代該對象钙态。返回值為函數(shù)塊的最后一行或指定return表達式慧起。

//Java
if (currentUser != null) {
    text.setText(currentUser.name)
}

//instead Kotlin
user?.let {
    println(it.name)
}
//源碼
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

2,with函數(shù)的kotlin和Java轉(zhuǎn)化
with函數(shù)和前面的幾個函數(shù)使用方式略有不同,因為它不是以擴展的形式存在的册倒。它是將某對象作為函數(shù)的參數(shù),在函數(shù)塊內(nèi)可以通過 this 指代該對象磺送。返回值為函數(shù)塊的最后一行或指定return表達式驻子。

可以看出with函數(shù)是接收了兩個參數(shù)灿意,分別為T類型的對象receiver和一個lambda函數(shù)塊,所以with函數(shù)最原始樣子如下:

//kotlin

fun main(args: Array<String>) {
    val user = User("Kotlin", 1, "1111111")

    val result = with(user) {
        println("my name is $name, I am $age years old, my phone number is $phoneNum")
        1000
    }
    println("result: $result")
}

//java

 public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      User user = new User("Kotlin", 1, "1111111");
      String var4 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
      System.out.println(var4);
      int result = 1000;
      String var3 = "result: " + result;
      System.out.println(var3);
   }

//源碼
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

3,run函數(shù)的kotlin和Java轉(zhuǎn)化
run函數(shù)實際上可以說是let和with兩個函數(shù)的結(jié)合體崇呵,run函數(shù)只接收一個lambda函數(shù)為參數(shù)缤剧,以閉包形式返回,返回值為最后一行的值或者指定的return的表達式域慷。

//kotlin

fun main(args: Array<String>) {
    val user = User("Kotlin", 1, "1111111")

    val result = user.run {
        println("my name is $name, I am $age years old, my phone number is $phoneNum")
        1000
    }
    println("result: $result")
}

//java

  public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      User user = new User("Kotlin", 1, "1111111");
      String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
      System.out.println(var5);
      int result = 1000;
      String var3 = "result: " + result;
      System.out.println(var3);
   }
//源碼
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

4,apply函數(shù)的kotlin和Java轉(zhuǎn)化
從結(jié)構(gòu)上來看apply函數(shù)和run函數(shù)很像荒辕,唯一不同點就是它們各自返回的值不一樣,run函數(shù)是以閉包形式返回最后一行代碼的值犹褒,而apply函數(shù)的返回的是傳入對象的本身抵窒。

//kotlin

fun main(args: Array<String>) {
    val user = User("Kotlin", 1, "1111111")

    val result = user.apply {
        println("my name is $name, I am $age years old, my phone number is $phoneNum")
        1000
    }
    println("result: $result")
}

//java

public final class ApplyFunctionKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      User user = new User("Kotlin", 1, "1111111");
      String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
      System.out.println(var5);
      String var3 = "result: " + user;
      System.out.println(var3);
   }
}

//源碼
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

5, also函數(shù)編譯后的class文件
also函數(shù)的結(jié)構(gòu)實際上和let很像唯一的區(qū)別就是返回值的不一樣,let是以閉包的形式返回叠骑,返回函數(shù)體內(nèi)最后一行的值李皇,如果最后一行為空就返回一個Unit類型的默認值。而also函數(shù)返回的則是傳入對象的本身

//kotlin

fun main(args: Array<String>) {
    val result = "testLet".also {
        println(it.length)
        1000
    }
    println(result)
}

//java

public final class AlsoFunctionKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      String var2 = "testLet";
      int var4 = var2.length();
      System.out.println(var4);
      System.out.println(var2);
   }
}

區(qū)別總結(jié)

非擴展函數(shù)的 run

fun <R> run(block: () -> R): R
一個無參數(shù)的lambda表達式宙枷,允許自定義返回值
這不是個擴展函數(shù)掉房,因此不能用對象點出來
但因為是頂級函數(shù),所以可以在任何地方直接調(diào)用慰丛,其一般用途應該主要是這種代碼:

run {
    // do something
}
val result = run {
    // do something
}
run卓囚、apply

fun <T, R> T.run(block: T.() -> R): R
fun <T> T.apply(block: T.() -> Unit): T
這兩個函數(shù)的共同點在于,參數(shù)都是T.()
因此在lambda中要以this來表示當前對象
不同點在于:run可以自定義返回值诅病,apply只能返回當前對象
使用示例:

"Hello"
    .run { this + " World" } // 在自身后面拼接字符串捍岳,并將結(jié)果返回
    .apply { println(this) } // 打印剛才拼接好的字符串
also、let

fun <T, R> T.let(block: (T) -> R): R
fun <T> T.also(block: (T) -> Unit): T

這兩個函數(shù)跟上面的兩個功能幾乎相同睬隶,可以看出let對run锣夹,also對apply
區(qū)別在于參數(shù)的lambda的參數(shù)部分變成了(T),因此要以it來表示當前對象
使用示例:

"Hello"
    .let { it + " World" } // 在自身后面拼接字符串苏潜,并將結(jié)果返回
    .also { println(it) } // 打印剛才拼接好的字符串
with

fun <T, R> with(receiver: T, block: T.() -> R): R

這個函數(shù)的作用是以一個指定對象的身份去調(diào)用特定的代碼银萍,并允許自定義返回值
感覺主要是為了新寫法設計的,一般用途應該是這樣的:

with ("Hello") {
    val str = this + " World"
    println(str)
}
takeIf恤左、takeUnless

fun <T> T.takeIf(predicate: (T) -> Boolean): T?
fun <T> T.takeUnless(predicate: (T) -> Boolean): T?

這兩個方法可以執(zhí)行一段代碼贴唇,這段代碼可以返回一個布爾值來控制之后的流程
對于takeIf:如果返回true,則這個函數(shù)會返回this飞袋,否則會返回null
而對于takeUnless則剛好與takeIf的行為相反
使用示例:

"Hello"
    .takeIf { it.length == 5 } // 判斷字符串的長度等于 5戳气,返回 true,因此 takeIf 函數(shù)會返回 this
    ?.run { this + " World!" } // 拼接字符串巧鸭,因為上一句沒返回 null瓶您,所以可以正常執(zhí)行
    ?.apply(::println) // 打印剛剛拼好的字符串
    ?.takeUnless { it.length == 5 } // 判斷字符串的長度等于 5,返回 false,因此 takeUnless 函數(shù)會返回 this
    ?.apply(::println) // 打印剛剛拼好的字符串
    ?.takeIf { it.length == 5 } // 判斷字符串的長度等于 5呀袱,返回 false贸毕,因此 takeIf 函數(shù)會返回 null
    ?.apply(::println) // 這句不會執(zhí)行!因為上一句返回了 null

```





文章來自:
      https://blog.csdn.net/u013064109/article/details/78786646
     http://www.reibang.com/p/1f139e3cfb49







最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夜赵,一起剝皮案震驚了整個濱河市明棍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寇僧,老刑警劉巖摊腋,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘁傀,居然都是意外死亡兴蒸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門心包,熙熙樓的掌柜王于貴愁眉苦臉地迎上來类咧,“玉大人,你說我怎么就攤上這事蟹腾『弁铮” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵娃殖,是天一觀的道長值戳。 經(jīng)常有香客問我,道長炉爆,這世上最難降的妖魔是什么堕虹? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮芬首,結(jié)果婚禮上赴捞,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布署咽。 她就那樣靜靜地躺著麻裁,像睡著了一般泼诱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音掰派,去河邊找鬼。 笑死左痢,一個胖子當著我的面吹牛靡羡,可吹牛的內(nèi)容都是我干的系洛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼亿眠,長吁一口氣:“原來是場噩夢啊……” “哼碎罚!你這毒婦竟也來了磅废?” 一聲冷哼從身側(cè)響起纳像,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拯勉,沒想到半個月后竟趾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡宫峦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年岔帽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片导绷。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡犀勒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妥曲,到底是詐尸還是另有隱情贾费,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布檐盟,位于F島的核電站褂萧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏葵萎。R本人自食惡果不足惜导犹,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羡忘。 院中可真熱鬧谎痢,春花似錦、人聲如沸卷雕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爽蝴。三九已至沐批,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝎亚,已是汗流浹背九孩。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留发框,地道東北人躺彬。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宪拥。 傳聞我的和親對象是個殘疾皇子仿野,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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