小小知识点:Unit相当于void,但Unit是一个类型,而void是一个关键字,表示不用返回值
一. 函数
1.1定义:
fun + 函数名(参数 :参数类型) :返回值类型{}
例:
fun method1( a : Int, b : Int) : String{
return "a + b"
}
不加权限修饰符默认是public
看一下反编译成Java代码的效果:
@NotNull
public static final String method1(int a, int b) {
return "a + b";
}
注意:不能在不同的kt文件里定义相同的函数,可以重载,即参数个数及类型或返回值不一样
1.2 函数的默认参数:
fun method1( a : Int, b : Int = 47) : String{
return "a + b"
}
这样在调用函数的时候可以选择赋一个值,也可以选择赋俩个值
如:
fun main() {
println(method1(40));
println(method1(20,20))
}
fun method1( a : Int, b : Int = 47) : Int{
return a + b
}
运行结果:
注意:默认参数得在最后一个,否则在赋值的时候可能报错
如:
此时解决方法有俩种:
- 调用方法的时候给a也一块赋值
- 利用具名参数这一性质赋值
println(method1(10,40))//将a也一并赋值了
println(method1(b = 20))//具名参数赋值给没有默认值的参数
二. 匿名函数
1.1第一种匿名函数写法(必须指明返回值的类型)
var/val 函数名 :(参数类型) -> 返回值类型{参数名 ->
具体函数内容
}
//声明匿名函数,()为输入的参数, -> 后面为输出的内容,就是返回值
var method2 : () -> Unit //
method2 = {
print("我是方法2")
} //method2的{}里面就是匿名函数
method2() //调用匿名函数
也可以像下面一样:
var method3 : (Int,Int,Int) -> String = { a, b, c ->
var d = a + b + c
"我是方法3"
}
println(method3(1,2,3))
//输出:我是方法3
说明:a, b, c就是参数名称, 返回值默认是最后一行
1.2 第二种匿名函数写法(利用出色的类推到机制,因此不用指明返回值类型)
写法如下:
var/val 函数名 = {参数名:参数类型 ->
函数具体逻辑
}
var method4 = { a : Int, b : Int ->
"我是方法四"
}
println(method4(1,2))
//输出:我是方法四
好处 ->后面不用强调返回类型,可以返回任意类型值
又如:
var method4 = {a: Int, b: Int ->
var c = "我是方法四"
1
}
println(method4(1,2))
//输出:1
var method4 = {a: Int, b: Int ->
var c = "我是方法四"
true
}
println(method4(1,2))
//输出:true
说明 : 匿名函数可以省去return,返回值是最后一行代码
三. it关键字的使用
var method5 :(String) -> String = {
"$it"
}
println(method5("我是方法五"))
//输出:我是方法五
当匿名函数的参数只有一个的时候,it 就是它的参数名称
四. lambda(浅谈,后期再详细写一篇关于lambda的文章)
其实上述的匿名函数就是lambda,关于lambda的特性,美妙之处之后细谈
五.参数是函数的 函数(类比Java,参数是接口)
var method6 : (Int,Int,(Int,Int)->Unit) -> Unit = {a,b,add->
add(a,b);
}
method6(10,10){ a : Int, b : Int ->
a + b
println("$a + $b = ${a+b}")
}
//运行结果:10 + 10 = 20
说明:类比Java:( Int, Int ) -> Unit 相当于传入了一个接口,而这个接口里有一个方法
void add(int a, int b) {
打印a + b的值
}
六. 内联函数的声明inline
当函数的参数有lambda表达式时,需要将该函数声明成内联函数,可以降低损耗
对于函数:
fun method1( a : Int = 10, b : Int, add : (Int, Int)->Int) : Int{
return add(a,b)
}
1.1未声明未内联函数时:反编译的结果:
public static final int method1(int a, int b, @NotNull Function2 add) {
Intrinsics.checkNotNullParameter(add, "add");
return ((Number)add.invoke(a, b)).intValue();
}
// $FF: synthetic method
public static int method1$default(int var0, int var1, Function2 var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var0 = 10;
}
return method1(var0, var1, var2);
}
缺点:在反编译成Java代码之后会多出一些对象来满足lambda表达式的执行,性能损耗严重
1.2声明了 内联函数后
inline fun method1( a : Int = 10, b : Int, add : (Int, Int)->Int) : Int{
return add(a,b)
}
来看一下反编译的结果:
public static final int method1(int a, int b, @NotNull Function2 add) {
int $i$f$method1 = 0;
Intrinsics.checkNotNullParameter(add, "add");
return ((Number)add.invoke(a, b)).intValue();
}
// $FF: synthetic method
public static int method1$default(int a, int b, Function2 add, int var3, Object var4) {
if ((var3 & 1) != 0) {
a = 10;
}
int $i$f$method1 = false;
Intrinsics.checkNotNullParameter(add, "add");
return ((Number)add.invoke(a, b)).intValue();
}
。。。尴尬了一波,我这边写的测试案例并不能很好的展示inline的优点,早晚还会再写一个例子展现一下内联的好处
七.函数引用
fun method7( a : Int, b : Int) : Unit{
println("$a + $b = ${ a + b}")
}
var method6 : (Int,Int,(Int,Int)->Unit) -> Unit = {a,b,add->
add(a,b);
}
method6(5,5,::method7)//调用method6,传入了method7
//输出: 5 + 5 = 10
综上:在闯入一个函数类型作为参数时,要使用 :: 符号将一个函数变成函数对象
var oj = ::method7
var oj2 = oj;
method6(20,20,oj2)
//效果与上面一样
八.函数作为返回值类型的函数
1.1具名函数
fun method9(a: Int,b: Int) : Int{
return a + b
}
fun method8 (a:Int,b:Int) : (Int,Int) -> Int {
// return {c:Int,d:Int ->
// a + b
// }
return ::method9
}
var resultMethod = method8(10,15)
println(resultMethod(10,15))
//调用method8,返回一个函数
1.2匿名函数
fun method9(a: Int) : Int{
return a
}
var method12 : (Int) -> (Int)->Int = {
var method13:(Int)->Int = { c->
10
}
::method9
}
返回值为函数的匿名函数 返回值必须是一个具名函数,否则报编译错误
例如:
=