当前位置: 首页 > news >正文

【Kotlin】函数

1 常规函数

1.1 无参函数

fun main() {myFun()
}fun myFun() {println("myFun") // 打印: myFun
}

1.2 有参函数

        1)常规调用

fun main() {myFun("myFun") // 打印: myFun
}fun myFun(str: String) {println(str)
}

         2)形参指定默认值

fun main() {myFun() // 打印: abc
}fun myFun(str: String = "abc") {println(str)
}

         3)实参指定变量名

fun main() {myFun(b = 123, a = "abc") // 打印: abc123
}fun myFun(a: String, b: Int) {println(a + b)
}

1.3 有返回值函数

        1)常规调用

fun main() {var c = add(3, 5)println(c) // 打印: 8
}fun add(a: Int, b: Int): Int {return a + b
}

        说明:对于无返回值类型函数,其返回类型为 Unit,如下,也可以省略不写。

fun myFun(str: String): Unit {println(str)
}

         2)单行函数体简化

        当函数内部只有一行代码时,可以简化如下。

fun main() {var c = add(3, 5)println(c) // 打印: 8
}fun add(a: Int, b: Int): Int = a + b

1.4 可变长参数函数(vararg)

        1)常规调用

fun main() {myFun("aa", "bb", "cc") // 打印: aa、bb、cc
}fun myFun(vararg parms: String) {for (str in parms) {println(str)}
}

        说明:函数的可变长参数个数最多为 1 个。 

        2)使用数组接收可变长参数

fun main() {myFun("aa", "bb", "cc") // 打印: 3
}fun myFun(vararg parms: String) {var arr: Array<out String> = parmsprintln(arr.size)
}

        3)将数组传给可变长参数函数

fun main() {var arr: Array<String> = arrayOf("aa", "bb", "cc")myFun(*arr)  // 打印: 3myFun("xx", *arr, "yy")  // 打印: 5
}fun myFun(vararg parms: String) {println(parms.size)
}

2 函数类型变量

2.1 函数类型变量

        1)无参函数变量

fun test() {println("test")
}fun main() {var myFun: () -> Unit = ::testmyFun() // 打印: test
}

        2)有参函数变量

fun test(a: Int, b: String): Unit {println("test, $a, $b")
}fun main() {var myFun: (Int, String) -> Unit = ::testmyFun(123, "abc") // 打印: test, 123, abc
}

        3)有返回值函数变量

fun test(a: Int, b: Int): Int {return a + b
}fun main() {var myFun: (Int, Int) -> Int = ::testprintln(myFun(3, 5)) // 打印: 8
}

2.2 匿名函数

        匿名函数即没有名字的函数,在声明函数变量时,可以指向一个匿名函数。

fun main() {var myFun: (Int, Int) -> Int = fun(a: Int, b: Int): Int {return a + b}println(myFun(3, 5)) // 打印: 8
}

        可以使用 Lambda 表达式简化如下。

fun main() {var myFun: (Int, Int) -> Int = { a, b ->a + b}println(myFun(3, 5)) // 打印: 8
}

3 内联函数(inline)

        内联函数是使用 inline 关键字修饰的函数,编译后会自动将函数体内的代码复制到调用处,以优化代码执行效率。

3.1 常规内联函数

        Test.kt

fun main() {myFun()
}inline fun myFun() {println("内联函数")
}

        以上代码经过编译运行后,依次点击【Tools → Kotlin → Show Kotlin Bytecode】,生成字节码文件。

        再点击 DeCompile 按钮反编译字节码文件,会生成对应的 Java 文件。

public final class TestKt {public static final void main() {String var1 = "内联函数";System.out.println(var1);}public static void main(String[] var0) {main();}public static final void myFun() {String var1 = "内联函数";System.out.println(var1);}
}

        说明:可以看到 myFun 函数里的代码被复制到调用处了。 

3.2 带 return 的嵌套内联函数

        1)return 不带标签

fun main() {outFun {println("inFun")return // 等价于: return@main}println("main end") // 未打印
}inline fun outFun(inFun: () -> Unit) {inFun()println("outFun end") // 未打印
}

        运行结果如下。

inFun

        "outFun end" 和 "main end" 未打印,这是因为内联函数会直接将 return 语句复制到 main 函数中。

        2)return@标签

fun main() {outFun {println("inFun")return@outFun}println("main end")
}inline fun outFun(inFun: () -> Unit) {inFun()println("outFun end")
}

        运行结果如下。

inFun
outFun end
main end

4 泛型函数

        泛型的类型检查只存在于编译阶段,在源代码编译之后,不会保留任何关于泛型类型的内容,即类型擦除。

4.1 简单泛型函数

        1)单泛型参数

fun main() {myFun(123)  // 打印: 123myFun("abc")  // 打印: abcmyFun(true)  // 打印: truemyFun(null)  // 打印: null
}fun <T> myFun(param: T) {println(param)
}

        2)多泛型参数

fun main() {var res: Boolean = myFun("abc", 123, true) // 打印: abc, 123println(res) // 打印: true
}fun <R, T, S> myFun(a: T, b: S, c: R): R {println("$a, $b")return c
}

4.2 类中泛型函数

fun main() {var c1: MyClass<String> = MyClass()c1.myFun("abc") // 打印: abcvar c2: MyClass<Int> = MyClass()c2.myFun(123) // 打印: 123
}class MyClass<T> {fun myFun(a: T) {println(a)}
}

4.3 自动推断泛型类型

        Kotlin 提供了下划线(_)运算符可以自动推断类型。

fun main() {myFun<Int, _>()
}fun <S : Comparable<T>, T> myFun() {println("test _")
}

        Int 类和 Comparable 类的定义如下。由于 Int 继承了 Comparable<Int>,因此会自动推断 "_" 为 Int。

public interface Comparable<in T>
public class Int private constructor() : Number(), Comparable<Int>

4.4 抗变、协变和逆变

        1)抗变

        如下,Int 是 Number 的子类,Number 引用可以指向 Int 对象,但是 Data<Number> 引用不能指向 Data<Int> 对象,Data<Int> 引用也不能指向 Data<Number> 对象,该现象称为抗变。

        2)协变

        通过 out 关键字表示 Data<Number> 引用能指向 Data<Int> 对象,类似于 java 中的 "? extends Number"。

class Data<T>(var value: T)fun main() {var data1: Data<Int> = Data<Int>(1)var data2: Data<out Number> = data1println(data2.value) // 打印: 1// data2.value = 1 // 编译错误, setter方法被限制
}

        说明:协变后,不能修改协变元素。使用 out 修饰的泛型不能用作函数的参数,对应类型的成员变量 setter 方法会被限制,只能当做一个生产者使用。

        3)逆变

        通过 in 关键字表示 Data<Int> 引用能指向 Data<Number> 对象,类似于 java 中的 "? super Int"。

class Data<T>(var value: T)fun main() {var data1: Data<Number> = Data<Number>(1f)var data2: Data<in Int> = data1println(data2.value) // 打印: 1.0data2.value = 2var a: Any ?= data2.value // 只能用Any接收value
}

        说明:逆变后,只能使用 Any 接收逆变元素。使用 in 修饰的泛型不能用作函数的返回值,对应类型的成员变量 getter 方法会被限制,只能当做一个消费者使用。 

        4)通配 *

        在有些时候,我们可能并不在乎到底使用哪一个类型,我们希望一个变量可以接受任意类型的结果,而不是去定义某一个特定的上界或下界。在Kotlin 泛型中,星号(*)代表了一种特殊的类型投影,可以代表任意类型。

class Data<T>(var value: T)fun main() {var data1: Data<Int> = Data<Int>(1)var data2: Data<*> = data1 // Data<*>等价于Data<out Any>println(data2.value) // 打印: 1.0// data2.value = 2 // 编译错误, setter方法被限制var a: Any ?= data2.value // 只能用Any接收value
}

        说明:由于不确定具体类型,使用时只能是 Any 类型。 

4.5 泛型的界

        Kotlin 泛型中,可以为其指定上界。

        1)单上界

class Data<T: Number>(var value: T)fun main() {var data1: Data<Int> = Data<Int>(1)// var data1: Data<String> = Data<String>("abc") // 编译错误, 指定了上界为Numbervar data2: Data<*> = data1 // Data<*>等价于Data<out Number>println(data2.value) // 打印: 1.0// data2.value = 2 // 编译错误, setter方法被限制var a: Number = data2.value // 可以用Number接收value
}

        2)多上界

open class A {}
interface B {}class Data<T>(var value: T) where T: A, T: B

4.6 具化类型参数(reified)

        Kotlin 的内联(inline)函数可以使用 reified 关键字具化类型参数,允许在函数体内部检测泛型类型,因为这些类型信息会被编译器内嵌在调用点。但是,这只适用于内联函数,因为内联函数中的类型信息在编译时是可知的,并且实际类型会被编译到使用它们的地方。

        以下调用会编译报错。

         通过 inline 和 reified 修饰符,可以解决编译报错问题,如下。

inline fun<reified T> isType(value: Any) : Boolean {return value is T
}fun main() {println(isType<Int>("abc")) // 打印: falseprintln(isType<String>("abc")) // 打印: true
}

相关文章:

【Kotlin】函数

1 常规函数 1.1 无参函数 fun main() {myFun() }fun myFun() {println("myFun") // 打印: myFun } 1.2 有参函数 1&#xff09;常规调用 fun main() {myFun("myFun") // 打印: myFun }fun myFun(str: String) {println(str) } 2&#xff09;形参指定默…...

Unity生命周期函数解析

本文由 简悦 SimpRead 转码&#xff0c; 原文地址 mp.weixin.qq.com Unity生命周期函数解析 Unity 生命周期函数是在游戏对象的不同阶段被调用的方法&#xff0c;通过这些函数&#xff0c;我们可以在不同的时刻执行特定的代码。在这篇文章中&#xff0c;我们将一步步解析 Unit…...

【Qt】QTextEdit/QPlainTextEdit 实现 Tab 键多行缩进与反缩进

【Qt】QTextEdit/QPlainTextEdit 实现 Tab 键多行缩进与反缩进 文章目录 I - 主要原理II - 代码实现2.1 - 自定义类2.2 - 实现 Tab 缩进2.3 - 实现反缩进 III - 参考链接 I - 主要原理 由于 QTextEdit 和 QPlainTextEdit &#xff0c;都无法实现多行选中缩进与反缩进&#xff…...

C++缺陷与思考

数组隐式转换为指针 size_t func(int a[10]) {return sizeof(a); }int a[100]; func(a); // 指针大小 sizeof(a); // 数组大小函数的参数看似是一个数组形式&#xff0c;但事实上他已经退化为指针了&#xff0c;也就是等价于size_t func(int* a)&#xff0c;而数组作为参数传…...

无公网ip环境使用DS file软件远程访问内网群晖NAS中储存的文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用程序具有…...

软件工程基础

本博客地址&#xff1a;https://security.blog.csdn.net/article/details/136446772 一. 软件工程 1、软件危机。具体表现为&#xff1a;软件开发进度难以预测、软件开发成本难以控制、软件功能难以满足用户期望、软件质量无法保证、软件难以维护和软件缺少适当的文档资料。 …...

alzet供应商你值得拥有

在20世纪70年代&#xff0c;ALZE公司研发出来一款巧妙的药物输送装置——Alzet osmotic pump。这款产品如胶囊般精致小巧&#xff0c;它既有胶囊的外表&#xff0c;也具有胶囊的作用。在Alzet osmotic pump中藏有可以装配药物溶液的空间。此款胶囊泵如同一个小投递员&#xff0…...

x86中的TSS与任务切换

前言 今天在学习《深入理解Linux内核》的时候&#xff0c;发现出现了一个新的名词TSS&#xff08;Task-State Segment&#xff09;&#xff0c;这还是我第一次了解到原来x86提供了硬件级别的任务切换功能&#xff0c;之前以为任务切换都是操作系统实现的来着&#xff0c;这里也…...

打造去中心化透明储蓄罐:Solidity智能合约的又一实践

一、案例背景 传统的储蓄罐通常是由个人或家庭使用&#xff0c;用于存放硬币或小额纸币。然而&#xff0c;这样的储蓄罐缺乏透明性&#xff0c;用户无法实时了解储蓄情况&#xff0c;也无法确保资金的安全性。 通过Solidity智能合约&#xff0c;我们可以构建一个去中心化…...

Java Mybatis数据库面试题

Java Mybatis数据库面试题 前言1、什么是 Mybatis&#xff1f;2、Mybaits 的优缺点&#xff1a;3、SQL 注入如何防止&#xff1f;4、MyBatis 框架适用场合&#xff1a;5、MyBatis 与 Hibernate 有哪些不同&#xff1f;6、#{}和${}的区别是什么&#xff1f;7、当表中的字段名和实…...

LeetCode-第14题-最长公共前缀

1.题目描述 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 2.样例描述 3.思路描述 按字符串数组每个数组的长度&#xff0c;将字符串数组从小到大排序&#xff1b;他们的公共前缀一定小于或等于最长元素长度…...

TCP/UDP模型:2024/2/29

作业1&#xff1a;TCP模型 服务器端&#xff1a; #include <myhead.h> #define SER_IP "192.168.199.129" #define SER_PORT 8899int main(int argc, const char *argv[]) {//1.创建用于连接的套接字文件int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){per…...

微信如何设置自动回复消息,提升沟通效率的?

在日常微信聊天过程中&#xff0c;我们可能会频繁遇到相同问题的客户提问&#xff0c;特别是对于从事销售工作的朋友们而言&#xff0c;客户添加好友后的第一句话常常为“在吗”或“你好”。当我们拥有大量好友&#xff0c;手动逐一回复可能会耗费大量时间。因此&#xff0c;自…...

PCIE的BAR空间

1.PCIe 简介 PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;是一种高速 串行计算机扩展总线标准&#xff0c;主要用于连接主板上的中央处理器&#xff08;CPU&#xff09;和 各种外部设备&#xff0c;如显卡、声卡、硬盘等。PCIe 总线取代了传统的 PC…...

11.互信息-机器学习模型性能的常用的评估指标

互信息&#xff08;Mutual Information&#xff09;是机器学习中常用的一种评估指标&#xff0c;特别是在无监督学习和聚类分析中。它用于衡量两个随机变量之间的相关性或相似性。 定义 给定两个随机变量X和Y&#xff0c;它们的互信息I(X;Y)定义如下&#xff1a; 其中&…...

SpringCloud(18)之Sleuth +Zipkin链路追踪

一、Zipkin介绍 Zipkin是一个开放源代码分布式的跟踪系统&#xff0c;它可以帮助收集服务的时间数据&#xff0c;以解决微服务架构中的延迟问 题&#xff0c;包括数据的收集、存储、查找和展现。每个服务向zipkin报告计时数据&#xff0c;zipkin会根据调用关系通 过Zipkin UI…...

GVA快速使用

1. clone 代码&#xff0c; 使用goland打开Server目录&#xff0c; 使用vsc打开前端web目录&#xff0c;运行后端&#xff0c;前端 gin-vue-admin后台管理系统 - 知乎 (zhihu.com) 2.了解端口配置 参考&#xff0c; 基于Go的后台管理框架Gin-vue-admin_go vue admin-CSDN博客…...

Linux文本处理三剑客:awk(内置函数详解笔记)

Linux系统中&#xff0c;AWK 是一个非常强大的文本处理工具&#xff0c;它的内置函数使得对文本数据进行处理更加高效和便捷。 本文将介绍 AWK 内置函数的几种主要类型&#xff1a; 算数函数字符串函数时间函数位操作函数其他常用函数 我们将使用一个示例文本文件来演示这些函…...

C++调用lua函数

C 调用Lua全局变量(普通) lua_getglobal(lua, "width");int width lua_tointeger(lua,-1);lua_pop(lua,1);std::cout << width << std::endl;lua_close(lua); 这几行代码要放到lua_pcall(lua, 0,0,0);之后才可以. C给lua传递变量 lua_pushstring(lua, …...

java找工作之Mybatis(入门及xml配置相关)

Mybatis 学习Mybatis就要学会查看官网&#xff0c;官网地址如下&#xff1a;<MyBatis中文网 > 1、简介 1.1什么是Mybatis MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...