当前位置: 首页 > 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
}
http://www.lryc.cn/news/310741.html

相关文章:

  • Unity生命周期函数解析
  • 【Qt】QTextEdit/QPlainTextEdit 实现 Tab 键多行缩进与反缩进
  • C++缺陷与思考
  • 无公网ip环境使用DS file软件远程访问内网群晖NAS中储存的文件
  • 软件工程基础
  • alzet供应商你值得拥有
  • x86中的TSS与任务切换
  • 打造去中心化透明储蓄罐:Solidity智能合约的又一实践
  • Java Mybatis数据库面试题
  • LeetCode-第14题-最长公共前缀
  • TCP/UDP模型:2024/2/29
  • 微信如何设置自动回复消息,提升沟通效率的?
  • PCIE的BAR空间
  • 11.互信息-机器学习模型性能的常用的评估指标
  • SpringCloud(18)之Sleuth +Zipkin链路追踪
  • GVA快速使用
  • Linux文本处理三剑客:awk(内置函数详解笔记)
  • C++调用lua函数
  • java找工作之Mybatis(入门及xml配置相关)
  • 如何保证 HTTPS 证书的有效性?
  • Qt 简约美观的动画 摆钟风格 第十季
  • Vue 3 中的 Composition API 详解
  • 利用Python爬取高德地图全国地铁站点信息
  • Vue 3 中的 Teleport 特性详解
  • 小白的matlab简单应用
  • 边缘计算网关在机床生产中的应用-天拓四方
  • maven配置文件(一)Settings配置
  • 选择何种操作系统作为网站服务器
  • 【LeetCode】升级打怪之路 Day 11:栈的应用、单调栈
  • 题目 1454: 蓝桥杯历届试题-蚂蚁感冒