【Kotlin】函数

news2024/9/24 18:09:59

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 可变长参数函数

        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> = parms
    println(arr.size)
}

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

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

fun myFun(vararg parms: String) {
    println(parms.size)
}

2 内联函数

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

2.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 函数里的代码被复制到调用处了。 

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

3 泛型函数

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

3.1 简单泛型函数

        1)单泛型参数

fun main() {
    myFun(123)  // 打印: 123
    myFun("abc")  // 打印: abc
    myFun(true)  // 打印: true
    myFun(null)  // 打印: null
}

fun <T> myFun(param: T) {
    println(param)
}

        2)多泛型参数

fun main() {
    var res: Boolean = myFun("abc", 123, true) // 打印: abc, 123
    println(res) // 打印: true
}

fun <R, T, S> myFun(a: T, b: S, c: R): R {
    println("$a, $b")
    return c
}

3.2 类中泛型函数

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

class MyClass<T> {
    fun myFun(a: T) {
        println(a)
    }
}

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

3.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> = data1
    println(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> = data1
    println(data2.value) // 打印: 1.0
    data2.value = 2
    var 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 类型。 

3.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") // 编译错误, 指定了上界为Number
    var 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

3.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")) // 打印: false
    println(isType<String>("abc")) // 打印: true
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++:设计包含min 函数的栈

目录 题目 代码实现 输出 题目 定义栈的数据结构&#xff0c;要求添加一个min 函数&#xff0c;能够得到栈的最小元素。 要求函数min、push 以及pop 的时间复杂度都是O(1)。 代码实现 #include <iostream>template<typename T>class stack { public:stack() {…

React富文本编辑器开发(四)

上一节我们做了块级元素的格式操作&#xff0c;这节我们来讲行内元素的相关操作。行内元素的样式一般指 粗体、斜体、代码或 删除线等 。通过前一章的内容得知&#xff0c;元素的渲染是通过渲染器来呈现的&#xff0c;块级元素通过指定 renderElement, 行内元素&#xff08;即内…

vxe-table编辑单元格动态插槽slot的使用

业务场景&#xff1a;表格中只有特定某一行的的单元格可以编辑&#xff0c;列很多&#xff0c;为每个列写个插槽要写很多重复代码&#xff0c;所以这里使用动态插槽&#xff0c;简化代码量。显示编辑图标&#xff0c;点击编辑图标隐藏。失去焦点保存调后台接口。 解决办法&…

【C语言】文件及文件操作详解(fseek,ftell,rwind)

目录 1. 为什么使用文件 2. 什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3. 二进制文件和文本文件 4. 文件的打开和关闭 4.1 流和标准流 4.1.1 流 4.1.2 标准流 4.2 文件指针 4.3 文件的打开和关闭 5. 文件的顺序读写 6.文件的随机读写 6.1 fseek 6.2 ft…

解决Keepalived “脑裂”(双VIP)问题

1. 检查广播情况 yum install tcpdump -y tcpdump -i ens33 vrrp -n master 192.168.80.130 与 backup: 192.168.80.131都在广播&#xff0c;正常情况下backup应该是不在广播的&#xff0c;所以可以判断存在防火墙屏蔽vrrp问题&#xff0c;需要设置VRRP过掉防火墙&#xff0…

浏览器常见问题及技巧总结-------( 更新中 )

浏览器常见问题及技巧总结 浏览器1 查找网页关键字2 如何利用技术下载网上图片3 百度搜索技巧 待续、更新中 浏览器 1 查找网页关键字 火狐firefox Ctrlf: 在网页中查找关键字2 如何利用技术下载网上图片 插件: 图片助手(但还是有水印, 比起原版的要差些)3 百度搜索技巧 1.…

SpringCloud gateway限流无效,redis版本低的问题

在使用springCloud gateway的限流功能的时候&#xff0c;配置RedisRateLimiter限流无效&#xff0c;后来发现是Redis版本过低导致的问题&#xff0c;实测 Redis版本为3.0.504时限流无效&#xff0c;改用7.0.x版本的Redis后限流生效。查了资料发现很多人都遇见过这个问题&#x…

【网站项目】314学生二手书籍交易平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

直流电压变送器更改从站地址

直流电压变送器采集模块转RS485修改地址 产品图片 产品说明书 修改从站地址 在串口助手上将默认的从站地址01h修改为0Bh 原从站地址&#xff1a;01h 修改参数&#xff1a;10h 通信参数允许修改寄存器&#xff1a;1b fe&#xff08;说明书里7166的十六进制&#xff09; 00 02…

c语言的数据结构:队列

1.队列存在的实现方式及其存在意义 1.1为什么队列使用单链表实现更好 动态内存分配&#xff1a;链表在C语言中通常使用动态内存分配&#xff0c;这意味着可以在运行时根据需要动态地添加或删除节点。这对于实现一个动态大小的队列非常有用&#xff0c;因为队列的大小可以在运…

Matlab在同一张图中如何加入多个图例

根据代码最终画出的图片如下&#xff1a; 其实原理很简单&#xff0c;就是在一张figure中画多个坐标轴&#xff0c;每个坐标轴都有对应的图例&#xff0c;之后再将多余坐标轴隐藏&#xff0c;只保留一个即可。 代码如下&#xff1a; clear all; close all;dd_linewidth 1;a …

2024广东水展即将开幕 | 聚焦净水行业热点抢占行业新机遇

2024广东水展即将开幕 | 聚焦净水行业热点抢占行业新机遇 随着消费升级和人们对环境健康的意识增强&#xff0c;人们除了关注净水产品的性能外&#xff0c;对产品的设计、服务、多应用场景化等需求也愈发多样化。节能环保、智能化成为产品迭代升级主要方向。据奥维云网数据显示…

二叉搜索树的范围和(Lc938)——DFS

给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1&#xff1a; 输入&#xff1a;root [10,5,15,3,7,null,18], low 7, high 15 输出&#xff1a;32示例 2&#xff1a; 输入&#xff1a;root [10,5,15,3,7,13,18,1,nul…

分享Selenium测试工具用来模拟用户浏览器的操作

执行JS的类库&#xff1a;execjs&#xff0c;PyV8&#xff0c;selenium&#xff0c;node pip list pip install selenium pip install xlrd pip install xlwt pip install PyExecJS pip install xlutils selenium测试工具可以用来模拟用户浏览器的操作&#xff0c;其支持的浏览…

使用lnmp环境部署laravel框架需要注意的点

1&#xff0c;上传项目文件后&#xff0c;需要chmod -R 777 storage授予文件权限&#xff0c;不然会报错file_put_contents(/): failed to open stream: Permission denied。 如果后面还是报错没有权限的话&#xff0c;就执行ps -ef |grep php查询php运行用户。然后执行chown …

简单数据类型和复杂数据类型

1. 简单数据类型 null是个特例: 2. 复杂数据类型 3. 堆和栈 注意&#xff1a; JavaScript 中是没有堆和栈的概念的&#xff0c;通过堆栈的概念可以更好的理解代码的一些执行方式&#xff0c;便于将来学习其他语言。 4. 简单数据类型传参 总结&#xff1a;简单数据类型传参传…

7款炫酷的前端动画特效分享(二)(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、SVG动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 jQuery拉开帷幕特效 基于jQuery实现的帷幕特效 点击右侧拉条 可以实现帷幕的收起也展开 非常的炫酷…

【论文笔记】Dynamic Occupancy Grids for Object Detection: A Radar-Centric Approach

原文链接&#xff1a;https://arxiv.org/abs/2402.01488 I. 引言 感知环境在自动驾驶中非常重要&#xff0c;但传统的方法将这一过程分为两方面&#xff1a;动态物体的检测和跟踪&#xff0c;以及使用占用网格表达静态环境。占用网格难以表达高度动态的物体&#xff0c;因此动…

全国青少年软件编程(Python)等级考试试卷(一级) 测试卷2021年12月

第 1 题 【 单选题 】 下面程序的运行结果是什么&#xff1f;&#xff08; &#xff09; a10 b5 ca*b print(c) A :10 B :15 C :50 D :5 正确答案:C 试题解析: 第 2 题 【 单选题 】 与a>b and b>c等价的是&#xff1f;&#xff08; &#xff09; A…

第七十二天 漏洞发现-Web框架中间件联动GobyAfrogXrayAwvsVulmap

第72天 漏洞发现-Web框架中间件&联动&Goby&Afrog&Xray&Awvs&Vulmap 知识点&#xff1a; 1、Bup简单介绍&使用说明 2、Xray简单介绍&使用说明 3、AWWS简单介绍&使用说明 4、Goby简单介绍&使用说明 5、Afrog简单介绍&使用说明 6、…