Kotlin中的“忍者”函数 —— 理解泛型的能力(KAD 12)
时间:Feb 8, 2017
原文链接:https://antonioleiva.com/generic-functions-kotlin/

Kotlin的一些特性组合起来与泛型混合使用创建函数可以极大的简化你的编码,且保证它的可读性。
在Kotlin库中,有几个函数非常实用,一旦你掌握它们的概念使用起来就非常容易。
with函数
尽管Kotlin标准库中有几个相似的函数,但是,我计划聚焦在with的各个部分上。
这个函数允许做什么?用了它,我们可以用一变量的代码块作为其上下文,这样就不需要每次使用它重复它的名字。
它们可以替代构建器,不需要为每个类创建特定构建器。
例如,回到前面文章的ViewGroup例子,可以转换这行代码:
val childViews = (0..viewGroup.childCount - 1).map { viewGroup.getChildAt(it) }
到:
with(viewGroup) {
val childViews = (0..childCount - 1).map { getChildAt(it) }
}
如你所见,括号内代码的行为就像是其在本类中。
那我们如何得到这样呢?我们在之前的扩展函数中已经见过了。
扩展函数作为其他函数的自变量
这事情越来越复杂了,但是这是非常有用的,你需要理解它。
你能够定义扩展函数为另一个函数的参数。
你怎样实现with函数执行前面的例子?最简单就是这样:
inline fun with(view: ViewGroup, f: ViewGroup.() -> Unit) {
view.f()
}
上面代码以参数形式接收ViewGroup,且一个用于ViewGroup的扩展函数。ViewGroup可无障碍执行那个函数。
但是,这限制较多。对数据的每种类型我们需要一个类似的函数?
当然不是。
泛型类型
我们能够十分容易地用泛型转换上面的函数。只需用T替换ViewGroup:
inline fun with(obj: T, f: T.() -> Unit) {
obj.f()
}
现在它就可以用于任何类型。例如:
with(textView) {
text = "Hello World"
visibility = View.VISIBLE
textSize = sp(14).toFloat()
}
但是,在我们开始讨论时,我们忽略一项重要的能力:构建器的角色。
泛型类型的返回值
如果我们想要一个真正的构建器,我们就需要以某种方式返回构建值:
inline fun with(obj: T, f: T.() -> Unit): T {
obj.f()
return obj
}
那样,我们的代码应该是这样:
val textView = with(TextView(this)) {
text = "Hello World"
visibility = View.VISIBLE
textSize = sp(14).toFloat()
}
注:sp() 是Anko库的函数,在这系列文章前面谈论过它。
如果你看函数的正式定义,它非常类似我们已经做的:
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
这里主要的区别在于扩展函数返回的值可能会不同传递参数。
为了获得与使用常规函数的相同结果,我们需要这样做:
val textView = with(TextView(this)) {
text = "Hello World"
visibility = View.VISIBLE
textSize = sp(14).toFloat()
this
}
最后一行意思是将返回执行扩展函数的对象。
其他有趣的函数
有一个函数功能非常类似我们在前一节得到的,它叫apply。
apply
这个函数作为对象的扩展函数,而不是对象的参数:
val textView = TextView(this).apply {
text = "Hello World"
visibility = View.VISIBLE
textSize = sp(14).toFloat()
}
let
如果相应的对象不是null,它将只需内部函数的代码:
textView?.text?.let { toast(it) }
仅当TextView和text都不为null,text将被显示在消息框(toast)中。
结论
结合扩展函数,利用泛型类型的能力,我们能做一些非常有趣的事情。
我鼓励你创建自己的函数以简化你的日常工作。
Kotlin中的“忍者”函数 —— 理解泛型的能力(KAD 12)的更多相关文章
- Lambda表达式在Kotlin中怎样工作的:setOnClickListener的转换(KAD 18)
作者:Antonio Leiva 时间:Mar 28, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin-android/ 虽然,我在其它文章讲过一点 ...
- 浅谈Kotlin中的函数
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/UV23Uw_969oVhiOdo4ZKAw作者:连凌能 Kotlin,已经被Android官方 ...
- 深入理解javascript中的立即执行函数(function(){…})()
投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...
- IIFE-js中(function(){…})()立即执行函数写法理解
介绍IIFE IIFE的性能 使用IIFE的好处 IIFE最佳实践 jQuery优化 在Bootstrap源码(具体请看<Bootstrap源码解析>)和其他jQuery插件经常看到如下的 ...
- 理解Vue中的Render渲染函数
理解Vue中的Render渲染函数 VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数.比如如下我想要实现 ...
- 数组中的reduce 函数理解
第一次见到reduce 是在js 的高级程序设计中,它的意思是把一个数组减少为一个数,举的例子是数组中元素的求和.它接受一个函数作为参数,函数又有两个参数,一个是prev, 前一个值,一个是next, ...
- 理解Underscore中的_.bind函数
最近一直忙于实习以及毕业设计的事情,所以上周阅读源码之后本周就一直没有进展.今天在写完开题报告之后又抽空看了一眼Underscore源码,发现上次没有看明白的一个函数忽然就豁然开朗了,于是赶紧写下了这 ...
- 在Kotlin中 使用js 函数
在Kotlin中 使用js 函数 import javax.script.Invocable import javax.script.ScriptEngineManager fun main(args ...
- 深入理解javascript中的立即执行函数
这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见,需要的朋友可以 ...
随机推荐
- Python开发第五篇
面向对象程序设计 面向过程编程:就是分析问题的解决步骤,按部就班的编写代码解决问题 函数式编程:就是把代码封装到函数中,然后在使用时调用封装好的函数 面向对象编程:把一类事物所共有的属性和行为提取出来 ...
- eplise中运行提示 A fatal error has been detected by the java runtime environment
今天一同事出现运行项目时,提示 A fatal error has been detected by the java runtime environment,具体表现是使用我们框架,不能正常的打印日 ...
- jenkin+centos 7 环境搭建
1.安装jenkins 首先安装好虚拟机和centos7操作系统 2.安装jdk 利用yum源来安装jdk(此方法不需要配置环境变量) 查看yum库中的java安装包 :yum -y list ja ...
- python-列表常用功能介绍
一.列表(list) 1.定义列表 names = [] #定义空列表 names = ['a','b','c'] #定义非空列表 2.访问列表中元素 >>> names = ['a ...
- hadoop中使用的Unsafe.java
今天查看hadoop源代码, 发现有个Unsafe.java 稍微总结下 优势 1 减少线程调度开销, Unsafe.java 通过采用非堵塞原子方式来减少线程调度开销 2 传统线程通信 ...
- django中的auth模块以及分页器
1.auth模块 auth模块是Django提供的标准权限管理系统,可以提供用户身份认证,和权限管理 auth可以和admin模块配合使用, 快速建立网站的管理系统 在INSTALLED_APPS中添 ...
- ssm整合-错误
[Err] 1005 - Can't create table 'imoocdb.ec_article' (errno: 150) 这个错误由外键约束引起的 java.lang.ClassCastEx ...
- tcp客户端socket
import socket # 和udp的区别显而易见,udp发送和接收的是一个元祖,因为udp是不建立连接的,只有得到了对方的端口和ip才能进行沟通. # 而tcp不是,tcp发送和接受的是一个字符 ...
- Docker自学纪实(五) 使用Dockerfile构建php网站环境镜像
一般呢,docker构建镜像容器的方式有两种:一种是pull dockerhub仓库里面的镜像,一种是使用Dockerfile自定义构建镜像. 很多时候,公司要求的镜像并不一定符合dockerhub仓 ...
- libvirt笔记(未完待续)
参考源地址:http://libvirt.org/formatdomain.html http://blog.csdn.net/qq250941970/article/details/6022094 ...