【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 对象
applyTthis
alsoTTit
runRRthis
letTRRit

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.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
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/473584.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Gateway新一代网关

Gateway新一代网关 1、概述 ​ Cloud全家桶中有个很重要的组件就是网关&#xff0c;在1.x版本中都是采用的Zuul网关&#xff1b; ​ 但在2.x版本中&#xff0c;zuul的升级一直跳票&#xff0c;SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul。 ​ 官网&…

HarmonyOS/OpenHarmony应用开发-HDC环境变量设置

hdc&#xff08;HarmonyOS Device Connector&#xff09;是 HarmonyOS 为开发人员提供的用于调试的命令行工具&#xff0c;通过该工具可以在 windows/linux/mac 系统上与真实设备或者模拟器进行交互。 hdc 工具通过 HarmonyOS SDK 获取&#xff0c;存放于 /Huawei/Sdk/openhar…

责任链模式(处理逻辑解耦)

前言 使用设计模式的主要目的之一就是解耦&#xff0c;让程序易于维护和更好扩展。 责任链则是将处理逻辑进行解耦&#xff0c;将独立的处理逻辑抽取到不同的处理者中&#xff0c;每个处理者都能够单独修改而不影响其他处理者。 使用时&#xff0c;依次调用链上的处理者处理…

RK3399 android10 移植SiS-USB触摸驱动

一&#xff0c;SiS USB触摸简介 SiS USB 触摸屏通常是一种外接式触摸屏设备&#xff0c;通过 USB 接口连接到计算机或其他设备上。这种触摸屏设备可以提供触摸输入功能&#xff0c;用户可以通过手指或触控笔在屏幕上进行操作&#xff0c;实现点击、拖动、缩放等操作。 SiS USB…

双向链表增删改查、遍历、倒置、销毁等——数据结构——day3

首先&#xff0c;我先把我的头节点写出来&#xff0c;里面有整理好的结构体 #ifndef __DOULINK_H__ #define __DOULINK_H__#include<stdio.h> #include<stdlib.h> #include<string.h>typedef struct student {int id;char name[50];int score; }DATA_TYPE; …

【数据可视化】Echarts中的其它图表

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. 绘制散点图2.1 绘制基本散点图2.2 绘制两个序列的散点图2.3 绘制带涟漪特效的散点图 3. 绘制气泡图3.1 绘制标准气泡图3.2 绘制各国人均寿命与GDP气泡图3.3 绘制城市A、城市B、城市C三个城市空气污染指数气…

负数,小数转换二进制

负数转换二进制 例&#xff1a;在带符号整数signed char的情况下&#xff0c;-57如何被表示成负数呢&#xff1f;在计算机中又是如何计算66-57呢&#xff1f; 解析 考虑int占有32位太长&#xff0c;因此使用只占8位的signed char类型来举例。57用二进制表示位00111001&#…

28-5 文件上传漏洞 - 图片马

一、文件内容检测 解析漏洞定义 控制文件是否被当做后端脚本处理 二、图片马绕过 图片马;在图片中包含一句话木马。利用解析漏洞如.htaccess 或文件包含漏洞,对图片马进行解析,执行其中的恶意代码。优势在于可以绕过多种防护机制。 三、图片马制作方法: # 一句话马示例…

nRF Sniffer在wireshark下的环境搭建

一、准备 nRF Sinffer 安装包&#xff1a; 直接下载&#xff1a;https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/desktop-software/nrf-sniffer/sw/nrf_sniffer_for_bluetooth_le_4.1.1.zip 官网下载&#xff1a; nRF Sniffer for Bluetooth…

Elasticsearch - Docker安装Elasticsearch8.12.2

前言 最近在学习 ES&#xff0c;所以需要在服务器上装一个单节点的 ES 服务器环境&#xff1a;centos 7.9 安装 下载镜像 目前最新版本是 8.12.2 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.2创建配置 新增配置文件 elasticsearch.yml http.host…

实现防抖函数并支持第一次立刻执行(vue3 + ts环境演示)

1、先看一效果&#xff1a; 2、实现思路&#xff1a; 使用定时器setTimeout和闭包实现常规防抖功能&#xff1b;增加immediate字段控制第一次是否执行一次函数&#xff08;true or false&#xff09;&#xff1b;增加一个flag标识&#xff0c;在第一次执行时&#xff0c;将标…

Aspose.PDF功能演示:在 JavaScript 中优化 PDF 文件

PDF 文件是一种普遍存在的文档共享格式&#xff0c;但它们有时可能会很大&#xff0c;导致加载时间变慢并增加存储要求。优化 PDF 文件对于确保无缝的用户体验至关重要&#xff0c;尤其是在 Web 应用程序中。因此&#xff0c;在这篇博文中&#xff0c;我们将探讨如何使用 JavaS…

软考网工学习笔记(6) 广域通信网

公共交换电话网&#xff08;pstn&#xff09; 在pstn是为了语音通信而建立的网络。从20世纪60你年代开始用于数据传输 电话网有三个部分组成&#xff1a; 本地回路 &#xff0c;干线 和 交换机 。 干线 和 交换机 一般采用数字传输和交换技术 &#xff0c;而 本地回路基本采…

Ubuntu18.04桌面版设置静态IP地址

引用: Ubuntu配置静态IP_ubuntu配置静态ip地址-CSDN博客 正文 默认Unbuntu 18.04 Desktop桌面版使用 netplan 管理网卡网络地址。使用Unbuntu 18.04 桌面版配置&#xff0c;可以通过桌面上的设置图标配置网卡的静态IP地址。 点击桌面右上角下拉框&#xff0c;点击“设置”按…

流畅的 Python 第二版(GPT 重译)(六)

第三部分&#xff1a;类和协议 第十一章&#xff1a;一个 Python 风格的对象 使库或框架成为 Pythonic 是为了让 Python 程序员尽可能轻松和自然地学会如何执行任务。 Python 和 JavaScript 框架的创造者 Martijn Faassen。 由于 Python 数据模型&#xff0c;您定义的类型可以…

【Linux】进程详解

目录 一、进程基本概念&#xff1a; 二、进程的五种基本状态&#xff1a; 三、Linux的进程状态&#xff1a; 四、控制进程状态相关指令&#xff1a; 五、僵尸进程与孤儿进程&#xff1a; 六、进程的优先级&#xff1a; 七、进程的四个重要特性&#xff1a; 八、环境变量…

ping 通ip,ping 不通域名

在linux 系统中&#xff0c;ping 通ip,ping 不通对应的域名时&#xff0c;可直接修改系统配置文件 vi /etc/hosts 加入 ip 域名

好就业三种专业#信息安全#云计算#网络工程

一、信息安全专业 根据2021年网络安全宣传周白皮书的观察结果&#xff0c;网络安全产业对于人才的需求正以高速增长的趋势呈现&#xff0c;当前网络安全行业存在着巨大的人才缺口&#xff0c;平均供求比例约为1:2。这一现象导致了资深人才的储备不足&#xff0c;并且新人才的培…

智慧校园数据可视化有什么好处?怎么推进数字化校园方案?

在当今数字化时代&#xff0c;越来越多学校开始实施智慧校园计划&#xff0c;旨在为学生和教师提供更高效、便捷的学习和教学环境。智慧校园运用互联网、大数据、人工智能等技术&#xff0c;对校园内各信息进行收集、整合、分析和应用&#xff0c;实现教学、管理、服务等多方面…

MySQL 索引的分类和优化

​ 优质博文&#xff1a;IT-BLOG-CN 索引是什么 &#xff1a; MySQL 官方对索引的定义&#xff1a;索引&#xff08;Index&#xff09;是帮助 MySQL 高效获取数据的数据结构。可以得到索引的本质&#xff1a;索引是数据结构。索引的目的在于提高查询效率。可以简单理解为&#…