【Kotlin】扩展属性、扩展函数
1 类的扩展
Kotlin 提供了扩展类或接口的操作,而无需通过类继承或使用装饰器等设计模式,来为某个类添加一些额外的属性或函数,我们只需要通过一个被称为扩展的特殊声明来完成。通过这种机制,我们可以将那些第三方类不具备的功能强行进行扩展,方便我们的操作。
1.1 扩展内置类
1.1.1 扩展属性
fun main() {
var str = "abc"
str.property = 5 // 打印: set property, value=5
var property = str.property // 打印: get property
println(property) // 打印: 10
}
var String.property: Int
set(value) {
println("set property, value=$value")
}
get() {
println("get property")
return 10
}
说明:扩展属性并不是真的往类中添加属性,也不会真的插入一个成员字段到类的定义中,导致没有变量存储我们的数据,我们只能明确定义一个 getter 和 setter 来创建扩展属性,才能让它使用起来真的像是类的属性一样。
如下,如果没有定义 getter 和 setter方法,将会报错如下。

1.1.2 扩展函数
fun main() {
var str = "abc"
str.myFun("xxx") // 打印: myFun, this=abc, value=xxx
}
fun String.myFun(value: String) {
println("myFun, this=$this, value=$value")
}
1.2 扩展自定义类
1.2.1 扩展属性
1)扩展新属性
fun main() {
var stu = Student()
stu.name = "Mary" // 打印: set name, value=Mary
var name = stu.name // 打印: get name
println(name) // 打印: Tom
}
class Student
var Student.name: String
set(value) {
println("set name, value=$value")
}
get() {
println("get name")
return "Tom"
}
2)扩展旧属性
fun main() {
var stu = Student("Jack")
stu.name = "Mary" // 无打印
var name = stu.name // 无打印
println(name) // 打印: Mary
}
class Student(var name: String)
var Student.name: String // 扩展属性不会生效
set(value) {
println("set name, value=$value")
}
get() {
println("get name")
return "Tom"
}
说明:如果扩展类中的同名同类型属性,扩展将不会生效。
1.2.2 扩展函数
1)扩展新函数
fun main() {
var stu = Student("Mary")
stu.test() // 打印: test, name=Mary
}
class Student(var name: String)
fun Student.test() {
println("test, name=$name")
}
2)扩展旧函数
fun main() {
var stu = Student("Mary")
stu.test() // 打印: inner, name=Mary
}
class Student(var name: String) {
fun test() {
println("inner, name=$name")
}
}
fun Student.test() { // 扩展函数不会生效
println("extended, name=$name")
}
说明:如果扩展类中的同名同参函数,扩展将不会生效。
1.3 重写父类的扩展函数
类的扩展是静态的,实际上并不会修改它们原本的类,也不会将新成员插入到类中,仅仅是将我们定义的功能变得可调用,使用起来就像真的有一样。同时,在编译时也会明确具体调用的扩展函数。
1.3.1 扩展属性
fun main() {
var stu: Student = Student()
var name1 = stu.name // 打印: Student, get name
println(name1) // 打印: Mary
var peo: People = stu
var name2 = peo.name // 打印: People, get name
println(name2) // 打印: Tom
}
open class People
class Student: People()
var People.name: String
set(value) {
println("People, set name, value=$value")
}
get() {
println("People, get name")
return "Tom"
}
var Student.name: String
set(value) {
println("Student, set name, value=$value")
}
get() {
println("Student, get name")
return "Mary"
}
1.3.2 扩展函数
fun main() {
var stu: Student = Student()
println(stu.type()) // 打印: Student
var peo: People = stu
println(peo.type()) // 打印: People
}
open class People
class Student: People()
fun People.type() = "People"
fun Student.type() = "Student"
1.4 匿名扩展函数
匿名函数的使用详见 →【Kotlin】函数。
fun main() {
var myFun: String.() -> Int = fun String.(): Int {
return this.length
}
println("abc".myFun()) // 打印: 3
}
可以使用 Lambda 表达式简化如下,Lambda 表达式的使用详见 → 【Kotlin】Lambda表达式。
fun main() {
var myFun: String.() -> Int = {
this.length
}
println("abc".myFun()) // 打印: 3
}
1.5 扩展函数作为参数
fun main() {
var len = "abc".len { this.length }
println(len) // 打印: 3
}
fun String.len(func: String.() -> Int): Int {
return func()
}
2 官方扩展函数
2.1 源码
Kotlin 提供了一些泛型扩展函数(在 Standard.kt 中),如:apply、also、run、let、takeIf、takeUnless 等。
apply、also、run、let 的区别如下,作用是执行 block 函数的内容,并且返回 T 或 block 的返回值,通常用于判空处理。
| 函数 | block是否为扩展函数 | block入参 | block返回值 | 函数返回值 | 访问 T 对象 |
|---|---|---|---|---|---|
| apply | 是 | 无 | 无 | T | this |
| also | 否 | T | 无 | T | it |
| run | 是 | 无 | R | R | this |
| let | 否 | T | R | R | it |
2.1.1 apply
public inline fun <T> T.apply(block: T.() -> Unit): T {
...
block()
return this
}
2.1.2 also
public inline fun <T> T.also(block: (T) -> Unit): T {
...
block(this)
return this
}
2.1.3 run
public inline fun <T, R> T.run(block: T.() -> R): R {
...
return block()
}
2.1.4 let
public inline fun <T, R> T.let(block: (T) -> R): R {
...
return block(this)
}
2.1.5 takeIf
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
...
return if (predicate(this)) this else null
}
2.1.6 takeUnless
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
...
return if (!predicate(this)) this else null
}
2.1.7 with
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
...
return receiver.block()
}
说明:with 不是扩展函数,但入参 block 是扩展函数。
2.1.8 to
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
2.1.9 toList
public fun <T> Pair<T, T>.toList(): List<T> = listOf(first, second)
public fun <T> Triple<T, T, T>.toList(): List<T> = listOf(first, second, third)
2.2 应用
2.2.1 apply 应用
fun main() {
var stu = Student()
test(stu)
}
fun test(stu: Student?) {
stu?.apply {
this.name = "Tom"
this.age = 23
}
println(stu) // 打印: [Tom, 23]
}
class Student {
var name: String? = null
var age: Int = 0
override fun toString(): String {
return "[$name, $age]"
}
}
说明:also、run、let 的应用与 apply 类似。
2.2.2 takeIf 应用
fun main() {
var str = "ABC"
var str2 = str.takeIf { it.length % 2 == 1 }?.let { it + it.reversed().substring(1) }
println(str2) // 打印: ABCBA
}
2.2.3 with 应用
fun main() {
var str = "ABC"
var len = with(str) { this.length }
println(len) // 打印: 3
}
声明:本文转自【Kotlin】扩展属性、扩展函数。
【Kotlin】扩展属性、扩展函数的更多相关文章
- Kotlin入门(33)运用扩展属性
进行App开发的时候,使用震动器要在AndroidManifest.xml中加上如下权限: <!-- 震动 --> <uses-permission android:name=&qu ...
- Kotlin代理属性--官方文档翻译
代理属性 Delegated Properties 本文为个人翻译的Kotlin官方文档, 原文连接: Delegated Properties 一些特定的常见类型的属性, 尽管我们可以在每次需要的时 ...
- Kotlin 扩展
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式. 扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响. 扩展函数 扩展函数可以在已有类中添加新的方法 ...
- Kotlin扩展作用域分析与扩展的根本作用解析
在上一次https://www.cnblogs.com/webor2006/p/11219358.html学习了Kotlin的扩展,继续这个话题继续拓展,首先提出这么一个问题:假如我们扩展的方法跟类中 ...
- SQL SERVER中的扩展属性
以前在SQL SERVER建表时,总看到扩展属性,但一直未使用过.今天研究下: 增加扩展属性: 语法: sp_addextendedproperty [ @name = ] { 'property_n ...
- 【C#】使用IExtenderProvider为控件添加扩展属性,像ToolTip那样
申明: - 本文适用于WinForm开发 - 文中的“控件”一词是广义上的说法,泛指包括ToolStripItem.MenuItem在内单个界面元素,并不特指继承自Control类的狭义控件 用过To ...
- ADO.Net(四)——扩展属性和配置文件应用
一.扩展属性 处理:有外键关系时将代号化信息处理成原始文字,让用户可看懂的(粗略解释) 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展 ...
- WIN8系统安装软件时提示"扩展属性不一致"的解决方法
单位新添加了两台T440P笔记本电脑,需要安装五笔输入法,同事一直安装不上.开始以为是WIN8系统跟输入法不兼容的问题,怀疑是输入法下载有误.于是直接在输入法官网下载了输入法,问题依旧:扩展属性不一致 ...
- PowerDesigner 16.5对SQL Server 2012 生成数据库时"不支持扩展属性"问题
团队合作设计一套系统数据模型,创建了PDM后,Table.View.Store Procedure等都创建好了,且创建了多个Schema方便管理这些数据库对象,但Table.view.Column等对 ...
- FME中Cass扩展属性转Shp的方法
问题:真受不了CAD中的注记,只能方便显示,难于数据交互.好在Cass把属性信息基本写在扩展属性中,但显示又成问题了.此事难两全!我们通过查看实体属性,需要把宗地界线的扩展属性提取出来.即组码为-3, ...
随机推荐
- 学会了MySql高级查询让你在工作中游刃有余
一.单元概述 通过本章的学习能够理解MySQL数据库中分组查询的含义,掌握常用分组函数的使用,掌握GROUP BY子句的使用规则,掌握分组后数据结果的条件过滤,掌握SELECT语句执行过程,理解子查询 ...
- 第131篇:如何上传一个npm包
好家伙, NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准. NPM是世界上最大的软件注册表. 1.首先我们 ...
- [C++/QT] 获取进程完整路径
气哭我了,我不就获取一下进程路径嘛,,,绕了好大一圈 主要是用到了GetModuleFileNameEx() 函数 食用方式如下 HANDLE hProcess = OpenProcess(PROCE ...
- Java 交换两个变量的值
1 //交换两个变量的值 2 // 1 3 int nu1 = 10; 4 int nu2 = 20; 5 6 System.out.println("nu1 = "+nu1+&q ...
- MySQL---面经
如果想要对 MySQL 的索引树有更深入的了解,掘金的小册子:<MySQL 是怎样运行的> MySQL 是怎样运行的 以下是常见面试题 MySQL日志 MySQL日志系统 redo_log ...
- 第142篇:原生js实现响应式原理
好家伙,狠狠地补一下代码量 本篇我们来尝试使用原生js实现vue的响应式 使用原生js,即代表没有v-bind,v-on,也没有v-model,所有语法糖我们都用原生实现 1.给输入框绑个变量 & ...
- Git: Host key verification failed(主机密钥验证失败)
换了新电脑Y7000 10750H,之前的项目提示这个,本以为删个什么文件,搜了一阵,没找到答案. 简单粗暴的方法就是再git clone一下,就ok了,这点很不爽.暂时先这么解决了.
- 32位数字电位器AD5228使用及调试总结
一 概念 什么是数字电位计? 数字电位器(Digital Potentiometer)亦称数控可编程电阻器,是一种代替传统机械电位器(模拟电位器)的新型CMOS数字.模拟混合信号处理的集成电路.数字电 ...
- 恒玄科技BES2500芯片OTA升级调试总结和源码分析
一 前言 bes2500芯片在tws耳机应用十分广泛,该芯片有着资源强大,音质好,大厂背书等特色.吸引了不少粉丝跟随. 最近在调试该芯片的ota功能,花费了一些时间,踩了一些坑,这里做一个总结和备忘吧 ...
- 微型跟踪器A产品体验和分析
跟踪器 这些年随着智能硬件的快速发展,各种新型的智能硬件层出不穷.在一个不起眼的赛道上,跟踪器的赛道一直比较沉寂,在这个一年几千万美金的市场上,玩家是有点少,产品更新不是很快.最近由于项目需要 ...