【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, ...
随机推荐
- macOS通过ssh使用PEM登录
在win上面可以使用XSHELL来登录类似于亚马逊这样的安全服务器,在mac上面就可以使用系统自带的命令工具来连接 使用命令 ssh -i key.pem [server] 如下: ssh -i ke ...
- 大众点评-CAT监控平台
前言 我们禀着发现问题,解决问题的方针,针对后台诸多的服务,如何实时监控接口性能和访问频率,还要统计大盘信息?CAT作为大众点评开源的系统监控平台项目,下面就介绍一下CAT平台的搭建步骤. CAT作为 ...
- Java 异常整合练习
1 package com.bytezero.throwable2; 2 3 /** 4 * 5 * @Description 异常练习 6 * @author Bytezero·zhenglei! ...
- Java 小练习(2) 利用面向对象的编程方法 设计类Circle计算圆的面积
1 package com.bytezero.exer; 2 /*** 3 * 4 * @Description 5 * @author Bytezero·zhenglei! Email:420498 ...
- Visual Studio部署C++环境下OpenCV库
本文介绍在Visual Studio 2022中配置.编译C++计算机视觉库OpenCV的方法. 1 OpenCV库配置 首先,我们进行OpenCV库的下载与安装.作为一个开源的库,我们直接在 ...
- harbor 安装
下载地址: https://github.com/goharbor/harbor/releases?page=1 下载了多个版本,发现仅v1.10.17版本支持GC清理,所以这里安装的v1.10.17 ...
- elementPlus使用el-icon
按着文档来撒 yarn add @element-plus/icons-vue main.ts import * as ElementIcons from '@element-plus/icons-v ...
- 第12章_MySQL数据类型精讲
第12章_MySQL数据类型精讲 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 1. MySQL中的数据类型 类型 类型举例 整数类型 TINYINT. ...
- linux程序运行结果在打印到屏幕的同时写入文件
1.使用script工具 script工具是一个非常使用的工具,可以把输出到终端的信息记录下来.使用方法如: (1)输入 script log.txt命令开始保存终端输出的信息 ,其中log.txt为 ...
- 阿里云Python UDP Server和client基础教程
壹: socket通信是常用的一种通信方式,熟练掌握,快速的入戏,是一个程序员必备的素质. 贰: 注意:udp和tcp的套接字: 服务端代码: #!/usr/bin/env python3 # -*- ...