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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章