【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, ...
随机推荐
- 【Azure Function】Function App和Powershell 集成问题, 如何安装PowerShell的依赖模块
问题描述 在Azure Function中创建一个PowerShell的函数后,其中使用了Get-AzMaintenanceUpdate,New-AzApplyUpdate 等指令,但是在执行时错误. ...
- Nebula Graph 1.0 Release Note
Nebula Graph 1.0 发布了.作为一款开源分布式图数据库,Nebula Graph 1.0 版本旨在提供一个安全.高可用.高性能.具有强表达能力的查询语言的图数据库. 基本功能 DDL & ...
- Java 从键盘读入学生成绩 找出最高分 并输出学生等级成绩 * 成绩>=最高分-10 等级为’A‘ * 成绩>=最高分-20 等级为’B‘ * 成绩>=最高分-30 等级为'C' * 其余 等级为’D‘
1 /* 2 * 从键盘读入学生成绩 找出最高分 并输出学生等级成绩 3 * 成绩>=最高分-10 等级为'A' 4 * 成绩>=最高分-20 等级为'B' 5 * 成绩>=最高分- ...
- netcat 命令介绍及使用示例
netcat 命令介绍及使用示例 nc(netcat)是一个强大的网络工具,它可以用于读取和写入数据流,支持 TCP 和 UDP 协议.它常被用于网络调试和网络服务的创建. 一.安装方法 centos ...
- Sealos 是企业节省成本的终极武器
本文通过多维度,多场景对比来阐述 Sealos 为企业节省大量成本,结合一些现有客户具体的实际情况全面分析成本模型,企业可以根据自己的实际情况来对号入座,看是否适合使用 Sealos. 云操作系统节省 ...
- Spring事务(一)-事务配置
事务是数据库操作最基本的单元,是逻辑上的一组操作,这一组操作在同一个会话中要么都执行成功,要么都失败,这也是事务的最基本特性--原子性.事务的作用是为了保证系统数据的正确性,因此,数据库应用程序中是会 ...
- H3C-IP路由器
定义 路由器负责将数据报文在IP网段之间进行转发 路由器负责将数据报文在IP网段之间进行转发 路由是指导路由器如何进行数据转发的路径信息 作用 路由器负责将数据报文在逻辑网段间进行转发 路由器是指导路 ...
- 接入移动手机号一键登录类的封装,app应用,php服务端类的封装与调用
需求:实现手机号一键登录,由于官方只有java的demo和jar包,没有php的sdk及demo <?php/* * 手机号一键登录加解密 */class Autophone{ const A_ ...
- ip 表单验证 vue iview
ip 表单验证 vue iview template <Row v-show="config.bindIP"> <Col span="12"& ...
- 玉蟾宫(悬线dp)
求最大子矩阵一般用采用悬线法 (包好用的牢底) 悬线法: [ 以这道题为例,我们将R称为障碍格子,将F称为非障碍格子] 我们选择任意一个非障碍格子,引出三条直线:左直 右直 上直 随后从这个点出发,分 ...