前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin---标准扩展函数

Kotlin---标准扩展函数

作者头像
None_Ling
发布2018-12-24 11:09:49
5170
发布2018-12-24 11:09:49
举报
文章被收录于专栏:Android相关

介绍

除了自定义扩展之外,Kotlin中也定义了很多的扩展函数,而这些扩展函数的接收类型是范型,也就是所有对象都可以使用。这些标准的扩展函数都放在了Standard.kt中。

从Kotlin的语言介绍中,可以知道,Kotlin在空指针以及null对象的控制、语句表达上有很多优势,很多优势也来源于Kotlin的扩展函数的支持。

接下来会介绍:

  • let
  • apply
  • run
  • takeIf
  • takeUnless
  • with

也会看看,这些函数是如何让空对象的代码更加优雅的表达。

let函数

首先来详细介绍一下let函数的定义,以及它是如何运行的。

代码语言:javascript
复制
/**
 * Calls the specified function [block] with `this` value as its argument and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
  1. 函数定义:
代码语言:javascript
复制
public inline fun <T, R> T.let(block: (T) -> R): R {
  • 使用inline关键字来标志这个函数是一个内联函数
  • <T,R>代表函数参数范型
  • T.let代表它是一个扩展函数,而接收参数是一个泛型
  • block:(T)->R代表函数的参数是一个代码块,而这个代码块接收参数T,并且返回R类型的对象
  • :R代表整个let函数返回类型是R类型

其中很重要的一个概念是:Kotlin中,所有的东西都是对象,所以代码块也是一个对象,可以使用变量引用。

  1. 函数体:
代码语言:javascript
复制
contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
  • contract代码块:主要为了告诉编译器,Lambda表达式会马上执行,并且只执行一次,因为在编译器编译的时候会对某些变量判空时,判断是否可以编译通过并且运行。
  • block(this):执行代码块中的代码,并且将调用扩展函数的对象作为参数传入,返回结果

let函数举例

例如下面的函数,如果student不为空的话,则会打印名字和年龄。

代码语言:javascript
复制
fun acceptStudent(student: Person?) {
        student?.let {
            println("Student Name:${it.mName}")
            println("Student Age:${it.mAge}")
        }
}

而如果这段代码用Java写的话,则是

代码语言:javascript
复制
if(student!=null) {
    println("student name:"+student.mName);
    println("student age:"+student.mAge)
}

apply函数

apply函数的定义如下:

代码语言:javascript
复制
/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

可以看到它和let函数差不多,只有一些区别:

  • block代码块中没有参数,仅仅只执行代码块的代码,但是可以使用this关键字来指向本对象
  • 函数的返回值是this,而block代码块没有返回值

因为它返回的this,也可以配合let扩展函数来使用

代码语言:javascript
复制
fun acceptStudent(student: Person?) {
        student?.apply {
            println("Apply Name...${this.mName}")
        }.let {
            println("let Age...${it?.mAge}")
        }
    }

run函数

run函数的原型是:

代码语言:javascript
复制
/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

可以看到,这个函数会执行代码块中的代码,并且将代码块执行的结果作为返回值返回。

例如: 在gardenPlantTest函数中,在run代码块中打印完字符串plant,如果plant不为空返回字符串长度,否则返回0,而result中保存的也就是代码块中返回的字符串长度

代码语言:javascript
复制
class GardenPlant {
    lateinit var plant: String;

    fun gardenPlantTest() {
        var result = plant.run {
            println("Plant String...$this")
            plant?.length
        }
        println("Plant Length:$result")
    }
}

takeIf函数

takeIf的函数原型: 将扩展对象T作为参数,执行predicate代码块的代码,如果在代码块中返回true,则返回对象T,如果返回false,则返回null

代码语言:javascript
复制
/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

例如: 如果plant字符串大于10,就可以采用,如果不行的话,则返回null,下面的代码块中只是表示可以在代码块中使用if等条件判断语句,只要最后返回的结果是boolean值就可以。

代码语言:javascript
复制
class GardenPlant {
    lateinit var plant: String;

    fun gardenPlantTest() {
        val filetrPlant = plant.takeIf {
            if (plant.length > 10) {
                plant.length > 10
            } else {
                plant.length < 10
            }
        }
        println("Plant String Length >9 :$filetrPlant")
    }
}

在代码块中返回值,不能使用return关键字,因为return关键字会返回整个函数,而不是代码块

takeUnless函数

takeUnless函数原型如下: 与takeIf不一样的是,返回的取值取反,来进行判断是否采用。

代码语言:javascript
复制
/**
 * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

with函数

with函数不是一个扩展函数,它的原型如下: 这个函数主要会接收一个对象,然后调用该对象的扩展代码块,然后返回代码块中的值。

代码语言:javascript
复制
/**
 * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

例如: 在plant对象中替换完字符后,返回length,并且赋值给plantLength

代码语言:javascript
复制
class GardenPlant {
    lateinit var plant: String;

    fun gardenPlantTest() {
        var plantLength = with(plant) {
            replace('w', 'r')
            length
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.12.03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • let函数
    • let函数举例
    • apply函数
    • run函数
    • takeIf函数
    • takeUnless函数
    • with函数
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档