转自:https://blog.csdn.net/guijiaoba/article/details/54615036

Kotlin之let,apply,with,run函数区别


重新整理

重新整理了各种函数的区别,请移步到这里。


以下作废


很长一段时间内都一直使用Kotlin这门语言,也只是纯粹使用简单语法,最近有时候写的代码,编辑器自动提示使用let等函数,然后就专门花点时间研究了下。

let

首先let()的定义是这样的,默认当前这个对象作为闭包的it参数,返回值是函数里面最后一行,或者指定return

fun <T, R> T.let(f: (T) -> R): R = f(this)
  • 1

简单示例:

fun testLet(): Int {
// fun <T, R> T.let(f: (T) -> R): R { f(this)}
"testLet".let {
println(it)
println(it)
println(it)
return 1
}
}
//运行结果
//testLet
//testLet
//testLet
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

可以看看最后生成的class文件,代码已经经过格式化了,编译器只是在我们原先的变量后面添加了let里面的内容。

public static final int testLet() {
String str1 = "testLet";
String it = (String)str1;
int $i$a$1$let;
System.out.println(it);
System.out.println(it);
System.out.println(it);
return 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

来个复杂一定的例子

fun testLet(): Int {
// fun <T, R> T.let(f: (T) -> R): R { f(this)}
"testLet".let {
if (Random().nextBoolean()) {
println(it)
return 1
} else {
println(it)
return 2
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

编译过后的class文件

public static final int testLet() {
String str1 = "testLet";
String it = (String)str1;
int $i$a$1$let;
if (new Random().nextBoolean())
{
System.out.println(it);
return 1;
}
System.out.println(it);
return 2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

apply

apply函数是这样的,调用某对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象

fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
  • 1

代码示例

fun testApply() {
// fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
ArrayList<String>().apply {
add("testApply")
add("testApply")
add("testApply")
println("this = " + this)
}.let { println(it) }
} // 运行结果
// this = [testApply, testApply, testApply]
// [testApply, testApply, testApply]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

编译过后的class文件

  public static final void testApply()
{
ArrayList localArrayList1 = new ArrayList();
ArrayList localArrayList2 = (ArrayList)localArrayList1;
int $i$a$1$apply;
ArrayList $receiver;
$receiver.add("testApply");
$receiver.add("testApply");
$receiver.add("testApply");
String str = "this = " + $receiver;
System.out.println(str);
localArrayList1 = localArrayList1;
ArrayList it = (ArrayList)localArrayList1;
int $i$a$2$let;
System.out.println(it);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

with

with函数是一个单独的函数,并不是Kotlin中的extension,所以调用方式有点不一样,返回是最后一行,然后可以直接调用对象的方法,感觉像是let和apply的结合。

fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
  • 1

代码示例:

fun testWith() {
// fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
with(ArrayList<String>()) {
add("testWith")
add("testWith")
add("testWith")
println("this = " + this)
}.let { println(it) }
}
// 运行结果
// this = [testWith, testWith, testWith]
// kotlin.Unit
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

class文件

 public static final void testWith()
{
Object localObject = new ArrayList();
ArrayList localArrayList1 = (ArrayList)localObject;
int $i$a$1$with;
ArrayList $receiver;
$receiver.add("testWith");
$receiver.add("testWith");
$receiver.add("testWith");
String str = "this = " + $receiver;
System.out.println(str);
localObject = Unit.INSTANCE;
Unit it = (Unit)localObject;
int $i$a$2$let;
System.out.println(it);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

run

run函数和apply函数很像,只不过run函数是使用最后一行的返回,apply返回当前自己的对象。

fun <T, R> T.run(f: T.() -> R): R = f()
  • 1

代码示例

fun testRun() {
// fun <T, R> T.run(f: T.() -> R): R = f()
"testRun".run {
println("this = " + this)
}.let { println(it) }
}
// 运行结果
// this = testRun
// kotlin.Unit
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

class文件

  public static final void testRun()
{
Object localObject = "testRun";
String str1 = (String)localObject;
int $i$a$1$run;
String $receiver;
String str2 = "this = " + $receiver;
System.out.println(str2);
localObject = Unit.INSTANCE;
Unit it = (Unit)localObject;
int $i$a$2$let;
System.out.println(it);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

总结

怎么样,是不是看晕了,没关系,我们来总结下。

函数名 定义 参数 返回值 extension 其他
let fun T.let(f: (T) -> R): R = f(this) it 闭包返回 是  
apply fun T.apply(f: T.() -> Unit): T { f(); return this } 无,可以使用this this 是  
with fun with(receiver: T, f: T.() -> R): R = receiver.f() 无,可以使用this 闭包返回 否 调用方式与其他不同
run fun T.run(f: T.() -> R): R = f() 无,可以使用this 闭包返回 是

Kotlin之let,apply,with,run函数区别(转)的更多相关文章

  1. [Java] Thread的start()和run()函数区别

    1.start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码: 通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状 ...

  2. Kotlin 之 let、with、run、apply、also 函数的使用

    一.内联拓展函数 let let 扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择:let函数另一个作用就是可以避免写一些判断null的操 ...

  3. 瞬间记住Javascript中apply与call的区别

    关于Javascript函数的apply与call方法的用法,网上的文章很多,我就不多话了.apply和call的作用很相似,但使用方式有区别 apply与call的第一个参数都是一个对象,这个对象就 ...

  4. 改变this指针的apply,call,bind的区别

    apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...

  5. apply()和call()的区别

    这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值. apply()接收两个参数:一个参数是在其中运行的作用域,另一个是参数数组(可以是Array实例,也可以是arg ...

  6. 【JavaScript】apply和call的区别在哪?

    我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...

  7. android SharedPreferences apply和commit的区别

    1.apply没有返回值而commit返回boolean表明修改是否提交成功2.apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘3.apply ...

  8. JavaScript之apply()和call()的区别

    我 在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示 例,总算是看的有点眉目了,在这里我做如下笔记,希望和 ...

  9. JS 中的this指向问题和call、apply、bind的区别

    this的指向问题 一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window. function a(){ console.log(this); //输出函数a中的th ...

随机推荐

  1. 【串线篇】Mybatis拓展之MBG

    MBG-逆向工程 一.介绍 MBG:MyBatis Generator:代码生成器: MyBatis官方提供的代码生成器:帮我们逆向生成: 正向: table----javaBean---BookDa ...

  2. Codeforces Round #538 (Div. 2) (CF1114)

    Codeforces Round #538 (Div. 2) (CF1114)   今天昨天晚上的cf打的非常惨(仅代表淮中最低水平   先是一路缓慢地才A掉B,C,然后就开始杠D.于是写出了一个O( ...

  3. hdu 5868:Different Circle Permutation 【Polya计数】

    似乎是比较基础的一道用到polya定理的题,为了这道题扣了半天组合数学和数论. 等价的题意:可以当成是给正n边形的顶点染色,旋转同构,两种颜色,假设是红蓝,相邻顶点不能同时为蓝. 大概思路:在不考虑旋 ...

  4. .Net Core 使用 Swagger 提供API文档

    1.运行环境 开发工具:Visual Studio 2017 JDK版本:.NET Core 2.0 项目管理工具:nuget 2.GITHUB地址 https://github.com/nbfujx ...

  5. 【HDU6662】Acesrc and Travel【树形DP】

    题目大意:给你一棵树,每个节点有一个权值,Alice和Bob进行博弈,起点由Alice确定,确定后交替选择下一个点,Alice目标是最终值尽可能大,Bob目标是尽可能小 题解:很明显是树形DP,那么考 ...

  6. LVS负载均衡中arp_ignore和arp_annonuce参数配置

    先简单的介绍下关于LVS负载均衡 LVS(Linux  Virtual Server)Linux服务器集群系统 针对高可伸缩,高可用服务的需求,给予IP层和内容请求分发的负载均衡调度解决方法,并在Li ...

  7. 使用nsenter进入docker容器后端报错 mesg: ttyname failed: No such file or directory

    通过nsenter 进入到docker容器的后端总是报下面的错,, [root@devdtt ~]# docker inspect -f {{.State.Pid}} mynginx411950 [r ...

  8. 【SpingBoot】 测试如何使用SpringBoot搭建一个简单后台1

    很久没写博客了,最近接到一个组内的测试开发任务是做一个使用SpringBoot 开发一个后台程序(还未完成),特写感想记录一下 1. 为什么选择SpringBoot ? 首先是目前很多公司的后台还是J ...

  9. Workflow:Workflow 百科

    ylbtech-Workflow:Workflow 百科 工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”.是对工作流程及其各操作步骤之间业务规则的抽象.概括描述.在计 ...

  10. English-GIS

    "Toposheet" 是 "Topographic sheet" 的简称,既地形图图幅的意思.