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关键字的使用: