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

Kotlin函数由易到难

函数的使用

//1.Unit相当于java的Void 返回值,如果没有返回就可以不写
fun test(): Unit{
}

//2.带参数的函数,返回为Int类型
fun test(a: Int, b: Int): Int{
	return a + b
}
fun test(a: Int,b: Int): Int = a + b //可以简写去掉"{} "用"="代替
fun test(a: Int,b: Int) = a + b //已知返回类型为Int,也可以省略Int

//3.参数设置默认值
fun test(a: Int = 6, b: Int = 10): Int{
	return a + b
}

注意:函数的形式参数默认情况下为常量,无法进行修改,如下截图
在这里插入图片描述

//4.函数内部也可以定义函数
	fun test(){
		fun inner(){
		//函数内部定义的函数,无限套娃
		}
		inner()//函数内的函数作用域是受限的,我们只能在函数内部使用
}

再谈变量

//1.顶级定义,直接写在Kt文件中,这个变量可以被所有的函数使用
var a: Int = a 
fun main() = Println(a)
fun test() = println(a)

以上也只是对变量的一些简单使用,现在变量的作用域被提升到顶层,它可以具有更多的一些特性,那么,我们就再来重写认识一下变量,声明一个变量的完整语法如下:

var <propertyName>[: <PropertyType>][= <property_initializer>]
    [<getter>]
    [<setter>]

对于变量的获取和设定,本质上都是通过其getter和setter函数来完成的,只不过默认情况下不需要我们去编写。
在这里插入图片描述
编译之后:
在这里插入图片描述
这是为了后续多态的一些性质而设计的。

//2.get函数,field 就是这个变量a
var a: Int = 5
    get() = field * 10
fun main(){
	println(a)
}
//打印结果:50

//3.set函数,重新给变量a 赋值,就是通过set函数
var a: Int = 5
    set(value){
    	field = value * 10
    }
fun main(){
	a = 90
	println(a)
}
//打印结果:900

递归函数

fun main(){
println(test(5)) //计算0-5的和
}
//这个函数实现了计算0-n的和的功能
fun test(n: Int): Int{
	if(n == 0) return 0   //当n等于0的时候就不再向下,而是直接返回0
	return n + test(n - 1) //n不为0就返回当前的n 加上test参数n-1的和
}
//5+ test(4) = 5 + 4 + teset(3) = 5 + 4 + 3 + test(3) = ....5 + 4 + 3 + 2 + 1 + 0

在这里插入图片描述
对于函数递归来说,这种方式效率低下,所以使用关键字 tailrec来优化上面的求和的函数,其原理是使用了while循环。
在这里插入图片描述
斐波那契数列的优化为:
在这里插入图片描述

函数类型的变量

//1.表示一个接收String作为参数返回值为Int的函数类型,如果返回类型不明确要写成Unit并且不可以省略。
var func:(String) -> Int

//2.方法的引用"::"
fun main(){
var func: (String) -> Int = ::test
println(func(""))
}
fun test (str: String): Int{
	return 666
}
//打印结果:666

//3.也可以写出匿名函数,没有函数名
var func: (String) -> Int = fun(str: String): Int{
		return 10
}
println(func(""))

//简化写法 var func:(String) -> Int = fun(str:String) = 10

//打印结果10

lambda表达式与高阶函数

//1.函数类型的变量匿名函数的方式可以使用lambda表达式{}来表示
fun main(){
var func: (String) -> Int = {
	println(it) //it代表传入的参数
	10
}
	func("Hello World")
}
//打印结果:Hello World

//2.两个参数,需要定义两个参数
fun main(){
var func: (String,String) -> Int = {a,b ->
	println(a)
	println(b)
	10
}
var func2: (String,String) -> Int = {_,b ->
	println(b) //假如这里不使用第一个参数,也可以使用_下划线来表示不使用
	10
}
	func("Hello World","haha")
}
/*
打印结果:
Hello World
haha
*/

函数传入的参数是函数就称为高阶函数,最直接的方式就是下面这样:

fun main(){
	val func: (String) -> Int = {10}
	test(func)
}
fun test(func: (String) -> Int){
	println(func("Hello World"))
}

//还可以这样写,传入一个lambda表达式
fun main(){
	test({
		println(it)
		20
	})
}
fun test(func: (String) -> Int){
	println(func("Hello World"))
}
/*
打印结果:
Hello World
20
*/

不过这样写还不够简洁,在Kotlin中,如果函数的最后一个形参是一个函数类型
,可以直接写在括号后面,就像下面这样:

test(){
		println(it)
		20
	}

由于小括号里面此时没有其他参数了,还可以继续省略,直接把小括号干掉:

test{
		println(it)
		20
	}

当然,如果在这之前有其他的参数,只能写成这样了:

test(10){
		println(it)
		20
	}
//这里两个参数,前面还有一个int类型参数,但是同意的最后一个参数是函数类型
fun test(a: Int,func: (String) -> Int){
	println(func("Hello World"))
}	

在Lambda中没有办法直接使用return语句返回,需要使用标签。
在这里插入图片描述
函数调用的是尾随lambda表达式
在这里插入图片描述
内联函数

添加关键字inline

fun main(){
	test()
}
inline fun test(){
	println("这是一个内联函数")
}

内联函数在编译的时候会把函数里面的内容直接放到调用的地方,可以查看编译后的class文件。
如:

fun main(){
	println("这是一个内联函数")
}

高阶函数也是一样的,如下:
在这里插入图片描述
有两个注意点:
1.内联函数中的形参不能作为值给到变量,除非在func前面加上"oninline"来修饰
2.内联高阶函数的Lambda参数可以直接写return,不指定标签
在这里插入图片描述
但是如果不指定标签返回的话就有问题了,会直接返回全局,不符合逻辑

fun main(){
test{ return }//内联高阶函数的Lambda参数可以直接写return指定标签
println("调用上面方法之后")
}
inline fun test(func: (String)-> Unit){
	func("HelloWorld")
	println("调用内联函数之后")
}
//打印结果:没有任何打印


//需要返回什么,打上标签,如返回test内联函数,如下:
fun main(){
test{ return@test }//这样就只会使test返回,而不会影响到外部函数了
println("调用上面方法之后")
}
inline fun test(func: (String)-> Unit){
	func("HelloWorld")
	println("调用内联函数之后")
}
/*打印结果:
调用内联函数之后
调用上面方法之后
*/

加上noinline关键字的使用:
在这里插入图片描述


http://www.kler.cn/a/383225.html

相关文章:

  • 我的 2024 年终总结
  • 突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除
  • pyinstaller打包资源文件和ini配置文件怎么放
  • OpenCV相机标定与3D重建(26)计算两个二维点集之间的部分仿射变换矩阵(2x3)函数 estimateAffinePartial2D()的使用
  • LLMs之PDF:MinerU(将PDF文件转换成Markdown和JSON格式)的简介、安装和使用方法、案例应用之详细攻略
  • 重温设计模式--命令模式
  • sqlserver使用bak文件恢复数据库
  • 解密 C# 中的迭代器与 yield:高效管理序列的艺术
  • 阿里云文本内容安全处理
  • Vue3中实现原生CSS完成圆形按钮点击粒子效果和定点旋转动画
  • 云联网:打造多云互联新生态,助力企业数字化转型
  • DICOM标准:重要概念——多种传输语法、私有数据元素标签、唯一标识符(UID)等详解
  • 梧桐数据库与GBase建表方式比较
  • 【机器学习】连续属性离散化与sklearn.preprocessing.KBinsDiscretizer
  • 非[I,P]结构的生成矩阵如何巧妙计算校验矩阵
  • 题目练习之二叉树那些事儿(续集)
  • Linux入门之vim
  • 深度学习常用开源数据集介绍【持续更新】
  • 《华为工作法》读书摘记
  • 【Git】Liunx环境下Git的使用:“克隆,提交,推送“
  • Sat-NeRF论文笔记和复现问题处理
  • 小游戏开发,出现了降本增效的技术?
  • 安装acondana3, Conda command not found
  • python项目实战---使用图形化界面下载音乐
  • 离线部署k8s1.21.2集群教程
  • CrackMe破解之Acid_burn