kotlin-學習-語法-Kotlin - Apply, Let, Run, With, Also - Higher Order Standard Functions 關鍵詞彙 文章 視頻 完整代碼

Kotlin致力於簡化開發過程。Kotlin的標準庫充滿了有用的類和函數,這些類和函數旨在實現這一承諾,即使在不存在內置語言特性的情況下。標準庫中的一類函數是Kotlin的高階函數apply, let, run, with和also。

通過刪除代碼重複,這些函數允許您編寫更簡潔、更簡單的代碼。警告!一旦你開始使用它們,你將無法想象沒有它們的編碼!

關鍵詞彙

文章

csdn-Kotlin系列之let、with、run、apply、also函數的使用

視頻

Reso Coder訂閱號-Kotlin - Apply, Let, Run, With, Also - Higher Order Standard Functions
對應代碼-Reso Coder


hello welcome to Reso coder in this tutorial .we are gonna take a look at a bunch of standard library core function like run 、with 、let and apply .they are higher-order functions which means that they actually execute a function themselves and the function which they execute is supplied to them by us .

some of these functions are actually extension but now without any further .let's get right to it . first up we need to have some kind of a class to demonstrate these functions on .

data class Person(var name: String,
                  var age: Int,
                  var job: String) {
    fun printPerson() = println(this.toString())
}

so we're gonna create a data class it will be called person and it is going to have three proerties and all of them are going to be mutable .so var name it's gonna be of type ,then also var age will be of type int and finally it will have var jao it will be of type string.

it's not gonna inherit from angthing and it's going to have one function printPerson and all that this function is gonna do is going to print line and it's going to print this person convert it to a string . or we can actually write it like this that to string ,so that it's more clear if you don't know what the data class is it's basically a classic class no pun intended it's just that it already has the two string and hashcode implemented .

fun String.println() = println(this)

you can also copy a data class so that is pretty nice and you can pick and choose which properties are going to be copied which not so that's pretty sweet and that's about it .then we are gonna one extension function on a String class so string and is going to be print line and this extentsion function will just print line of this string .

    val firstPerson = Person("John", 20, "Programmer")
    val secondPerson = Person("Dave", 30, "Bus Driver")

alright now let's go to main function and we are we are gonna create two people so while first person is going to be a person and its name will be John and he will be twenty years old and he will be a programmer
and then second person it's gonna be again person its name or his name will be David and he will be 30 years old and he will be a bus driver.

    //普通方式,沒使用高級函數
    val olderPerson = if (firstPerson.age >= secondPerson.age) firstPerson else secondPerson
    olderPerson.printPerson()

now let's suppose that you want to print the person which is older you could normally do it like this while older person it's equal to if firstPerson.age is greate or actually equl to secondPerson.age and then we want to return this if statement firstPerson are wise ,so else secondPerson is older.

and now we would write older person that print person. and that's how you would do it without these higher-order function.

    //run高階使用
    run {
        if (firstPerson.age >= secondPerson.age) firstPerson else secondPerson
    }.printPerson()

if you want to do the same thing but without creating a variable you would use run function and inside this function block you would put this precisely the same if statement all right and paste it in here and now you would print the person which this run returns .

if we check what's written in the documentation about this run function .it says that it calls the specified black and returns its result .

and it doest precisely that is executes all of the code all of the code between tis curly braces [花括號] and then whatever is returned .so firstPerson or secondPerson and actually we can see that it returns this run because there is this signed it this is returned from run and the secondPerson is also returned from run .
so that is returned and we can call then use it to print the older person .

    //高級函數with(可以省略this)
    with(firstPerson) {
        age += 1
        "Age is now $age"
    }.println()

when we have a with function as you can see here you need to specify a receiver of any type the receiver in this case will be our firstPerson this with function is useful when you want to modify an object and return what you want like in the run function above .
you can specify what you want to return .so let's modify this first person we can write this that age because this is a receiver and just like in any normal class you don't need to write this .

almost never so you can omit this keyword even in the with function and we can plus equal 1 this age ,and then we can return age is now and interpolate age and then we can print line whatever that was returned from this with function .

here we are using the extension function which we create for our Strings. when we actually run the code now we can see that the run and also the classical way of getting the older person prints out the same thing .

so this is older so it prints out Dave and then this with it returns is now 21 because we increment a age by 1 .

then similar to the with function is also a run function but unlike this ruan above this is an extension function on and kind of class so we can write firstPerson than run .
and now this firstPerson is automatically the receiver for this function .so this run function has actually a more concise syntax of with .

    //run高級
    firstPerson.run {
        age += 1
        "Age is now $age"
    }.println()

and also if 1st person was knowable you can do a check here so no save access operator and you would be good to go . so I would advise that you use run instead of with almost always like i don't even use with in my code ,because i didn't have any reason to use it . I always use run so again we put the same kind of code inside here like in with .
and then we can print line and it's going to do the same thing actually .

    firstPerson.let { modifiedPerson ->
        modifiedPerson.age += 1
        "Age is now ${modifiedPerson.age}"
    }.println()

and then let unlike with and run .let us passed argument and not a receiver and a receiver is this so we can actually emit this ,but remember we can always write this before H and it's going to be just fine but we omit this .
so why would we write that .

and let has an argument and not this receiver .so firstPerson that let and as you can see it right here that it is person not this is person and arguments can be renamed so we can rename it to modified person and then use it inside function so modified person that age again plus equals one ,then we want to return ages now and interpolate
and because we are gonna use an access operator inside it inisde the interpolation .we need to put two curly braces after the dollar sign and inside that we can write modify person the age and then we can also print line .

and when we run this after the with executes the age is to anyone after run executes the age is 22 ,and after let execute the age is 23 .

    secondPerson.apply {
        age += 1
        job = "Hot-dog seller"
    }.printPerson()

now are coming to my beloved higher-order function and that is apply .
it's again a generic extension function so we can write second person this time apply and apply is my most used standard library higher-order function .

it has a receiver this and ti returns also this which is the modified object so unlkie with run you cannot retrun some string or some in from here .it always returns the same object on which you call this apply ,you have no other choice.

if we look at the documentation so ctrl+Q it write here that it calls the specified function block with this value as its receiver and returns this value .

apply is used when you want to initialize an object and you cannot put all of the arguments in the constructor ,because for example the constructor doesn't accept all of the arguments which you want to supply it ,in this case we can write age plus equals 1 and we will change the secondPerson's job to be Hot-dog seller and then we can print the person .

basically apply is a replacement for writing secondPerson that age plus equals 1 and then again secondPerson that job equqls hot dog seller right blah blah blah we have a duplication of code here we are writing two times secondPerson .
but we can use apply and right secondPerson only once .so that is pretty nice on a sidenote in Android with ankle library there's also apply recursively which can modify all of the members of a view group .

so if you have a linearLayout I don't have it here I am using plain Kotlin here but let's suppose that we have a linearLayout if you are not an Android developer you can freely ignore this stuff .and it has a bunch of let's say textViews inside and we can apply recursively on this linearLayout and inside this we are going to be accessing all the individual view inside the linearLayout and not the linearLayout itself and and here we could check if this is textView and then set its texts size to be some kind of like sp 50sp .

right if you are using anko and if you want to learn how to use anko you can check out my tutorial by clicking on the cart in the corner .
and also in android this wouldn't be an error it would actually work .if you have anko installed .

    secondPerson.also {
        it.age += 1
        it.job = "YouTuber"
    }.printPerson()

and sometimes you want to use something like apply but you want to have a parameter which you can rename for example instead of a receiver .

for that there is also a function and it's called also . so as you can see here we are getting a person as an implicit it parameter and we an write it dot age plus quals 1 and it.job is youtube and then we can also print person and we could obviously rename it to be some kind of modified person like up above in let .


and now when we run this code you can see that both apply and also change the Dave Person successfully and that's it for this tutorial if you don't want to miss more tutorials like thsi subscribe to this channel and also hit the belly button so that you are gonna be notified about all of my new videos.


完整代碼

package younghare.grammers

fun main(args: Array<String>){
    val firstPerson = Person("John", 20, "Programmer")
    val secondPerson = Person("Dave", 30, "Bus Driver")

    val olderPerson = if (firstPerson.age >= secondPerson.age) firstPerson else secondPerson
    olderPerson.printPerson()

    //run函數使用的一般結構
    run {
        if (firstPerson.age >= secondPerson.age) firstPerson else secondPerson
    }.printPerson()

    //with函數和前面的幾個函數使用方式略有不同,因爲它不是以擴展的形式存在的。它是將某對象作爲函數的參數,在函數塊內可以通過 this 指代該對象。返回值爲函數塊的最後一行或指定return表達式。
    with(firstPerson) {
        age += 1
        "Age is now $age"
    }.println()

    //run函數的inline+lambda結構
    //run函數實際上可以說是let和with兩個函數的結合體,run函數只接收一個lambda函數爲參數,以閉包形式返回,返回值爲最後一行的值或者指定的return的表達式。
    firstPerson.run {
        age += 1
        "Age is now $age"
    }.println()

    //let擴展函數的實際上是一個作用域函數,當你需要去定義一個變量在一個特定的作用域範圍內,let函數的是一個不錯的選擇;let函數另一個作用就是可以避免寫一些判斷null的操作。
    //返回值爲函數塊的最後一行或指定return表達式。
    //場景一: 最常用的場景就是使用let函數處理需要針對一個可null的對象統一做判空處理。
    //場景二: 然後就是需要去明確一個變量所處特定的作用域範圍內可以使用
    firstPerson.let { modifiedPerson ->
        modifiedPerson.age += 1
        "Age is now ${modifiedPerson.age}"
    }.println()

    //從結構上來看apply函數和run函數很像,唯一不同點就是它們各自返回的值不一樣,run函數是以閉包形式返回最後一行代碼的值,而apply函數的返回的是傳入對象的本身。
    //apply一般用於一個對象實例初始化的時候,需要對對象中的屬性進行賦值。或者動態inflate出一個XML的View的時候需要給View綁定數據也會用到
    secondPerson.apply {
        age += 1
        job = "Hot-dog seller"
    }.printPerson()

    //also函數的結構實際上和let很像唯一的區別就是返回值的不一樣,let是以閉包的形式返回,返回函數體內最後一行的值,如果最後一行爲空就返回一個Unit類型的默認值。而also函數返回的則是傳入對象的本身
    secondPerson.also {
        it.age += 1
        it.job = "YouTuber"
    }.printPerson()
}

data class Person(var name: String,
                  var age: Int,
                  var job: String) {
    fun printPerson() = println(this.toString())
}

fun String.println() = println(this)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章