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】扩展属性、扩展函数的更多相关文章

  1. Kotlin入门(33)运用扩展属性

    进行App开发的时候,使用震动器要在AndroidManifest.xml中加上如下权限: <!-- 震动 --> <uses-permission android:name=&qu ...

  2. Kotlin代理属性--官方文档翻译

    代理属性 Delegated Properties 本文为个人翻译的Kotlin官方文档, 原文连接: Delegated Properties 一些特定的常见类型的属性, 尽管我们可以在每次需要的时 ...

  3. Kotlin 扩展

    Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式. 扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响. 扩展函数 扩展函数可以在已有类中添加新的方法 ...

  4. Kotlin扩展作用域分析与扩展的根本作用解析

    在上一次https://www.cnblogs.com/webor2006/p/11219358.html学习了Kotlin的扩展,继续这个话题继续拓展,首先提出这么一个问题:假如我们扩展的方法跟类中 ...

  5. SQL SERVER中的扩展属性

    以前在SQL SERVER建表时,总看到扩展属性,但一直未使用过.今天研究下: 增加扩展属性: 语法: sp_addextendedproperty [ @name = ] { 'property_n ...

  6. 【C#】使用IExtenderProvider为控件添加扩展属性,像ToolTip那样

    申明: - 本文适用于WinForm开发 - 文中的“控件”一词是广义上的说法,泛指包括ToolStripItem.MenuItem在内单个界面元素,并不特指继承自Control类的狭义控件 用过To ...

  7. ADO.Net(四)——扩展属性和配置文件应用

    一.扩展属性 处理:有外键关系时将代号化信息处理成原始文字,让用户可看懂的(粗略解释) 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展 ...

  8. WIN8系统安装软件时提示"扩展属性不一致"的解决方法

    单位新添加了两台T440P笔记本电脑,需要安装五笔输入法,同事一直安装不上.开始以为是WIN8系统跟输入法不兼容的问题,怀疑是输入法下载有误.于是直接在输入法官网下载了输入法,问题依旧:扩展属性不一致 ...

  9. PowerDesigner 16.5对SQL Server 2012 生成数据库时"不支持扩展属性"问题

    团队合作设计一套系统数据模型,创建了PDM后,Table.View.Store Procedure等都创建好了,且创建了多个Schema方便管理这些数据库对象,但Table.view.Column等对 ...

  10. FME中Cass扩展属性转Shp的方法

    问题:真受不了CAD中的注记,只能方便显示,难于数据交互.好在Cass把属性信息基本写在扩展属性中,但显示又成问题了.此事难两全!我们通过查看实体属性,需要把宗地界线的扩展属性提取出来.即组码为-3, ...

随机推荐

  1. js之以面向对象的形式书写贪吃蛇

    此代码存在一定的小bug,当蛇出边界之后存在一定的小问题 分析贪吃蛇功能需求: 1.食物 (1)每次生成一个,位置随意但不可超出规定范围 (2)每次蛇吃到食物之后,前一个食物消失同时新的食物又生成 ( ...

  2. 全表查询sql执行链路排查

    问题描述: 发现有sql查询全表数据,慢查询语句,根据druid上的sql监控查看到. 主要根据标红的列确定问题sql. 点击进去可以看到详细sql信息. 问题排查目标: 发现这个语句高层调用方特别多 ...

  3. 【Azure 微服务】新创建的Service Fabric集群,如何从本地机器上连接到Service Fabric Explorer(Service Fabric状态/错误查看工具)呢?

    问题描述 当在Azure中成功创建一个Service Fabric Cluster 服务后,我们能够在它的Overview页面中发现 Service Fabric Explorer的终结点,但是打开后 ...

  4. 【Azure 事件中心】Event Hub 消费端出现 Timeout Exception,errorContext中 LINK_CREDIT为0的解释

    问题描述 在使用Event Hub SDK消费数据过程中,出现大量的Timeout Exception,详细消息为: com.microsoft.azure.eventhubs.TimeoutExce ...

  5. 【Azure Redis 缓存】如何使得Azure Redis可以仅从内网访问? Config 及 Timeout参数配置

    问题描述 问题一:Redis服务,如何可以做到仅允许特定的子网内的服务器进行访问? 问题二:Redis服务,timeout和keepalive的设置是怎样的?是否可以配置成timeout 0? 问题三 ...

  6. 【Azure 应用服务】Azure Function 中运行Powershell 脚本,定位 -DefaultProfile 引发的错误

    问题描述 突然之间,使用PowerShell脚本 Get-AzVirtualNetwork 获取虚拟网络信息时,如果带上  -DefaultProfile $sub 参数,就出现 Azure cred ...

  7. Go语言VSCode开发环境配置

    最近学习Golang,先把开发环境配置好. 一.安装Go语言开发包 https://golang.google.cn/dl/ 按步骤安装即可,安装完成后需要设置Windows环境变量 配置好,做个测试 ...

  8. 2FA双因素认证 - 原理和应用

    主页 个人微信公众号:密码应用技术实战 个人博客园首页:https://www.cnblogs.com/informatics/ 引言 我们在登陆网站.或者通过VPN访问公司内网时,除了输入用户口令外 ...

  9. FreeRTOS教程1 基础知识

    1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) Keil µVision5 IDE(MDK-Arm) 野火DAP仿真器 2.学 ...

  10. $help console 里面的入口帮助文档

    $help console 里面的入口帮助文档 Object.defineProperty(window, '$help', { get: function() { // 这里面this是window ...