Kotlin 函数

  • 函数的定义
    • 普通函数
    • 形参&返回值
    • 带默认值
    • 具名参数
    • 可变参数
  • 函数嵌套
  • 函数当参数传递
  • Unit

Kotlin函数在设计上与Java相比有非常多的改动,并有独特性,尤其是函数可以当参数的形式传递,提供了更大的发挥空间,并且巧妙的运用Lambda表达式

函数的定义

普通函数
/**
 * 定义函数
 */
fun function(){
    println("Function 函数~")
}

@Test
fun main() {
    //调用
    function()
}
形参&返回值
/**
 * 定义函数
 */
fun function(code: Int, message: String): Boolean {
    println("Function 函数~ 接受到参数  code:${code}  message:${message}")
    return true
}

@Test
fun main() {
    //调用
   val isCall = function(200,"ok")
}
带默认值

可以看出带默认值的解决JAVA中的多态的定义,以及一些参数的常量的初始值

/**
 * 定义函数
 */
fun function(code: Int = 100, message: String = "未知"): Boolean {
    println("Function 函数~ 接受到参数  code:${code}  message:${message}")
    return true
}

@Test
fun main() {
    //调用
    val isCall1 = function()
    val isCall2 = function(200)
    val isCall3 = function(200, "ok")
}
具名参数

调用时可以有选择性的参数传值 参数昵称 = 参数值

/**
 * 定义函数
 */
fun function(code: Int = 100, message: String = "未知"): Boolean {
    println("Function 函数~ 接受到参数  code:${code}  message:${message}")
    return true
}

@Test
fun main() {
    //调用
    val isCall = function(message = "ok")

}
可变参数

怎么理解可变参数,在JAVA中有funcation(String... args) 可以接受N个String参数,而在Kotlin也可以这么定义,是不过是使用关键字vararg来定义

/**
 * 定义函数
 */
fun function(vararg rarg: String): Unit {
    println("Function 函数~ 接受到参数  rarg 长度:${rarg.size}  ")
}

@Test
fun main() {
    //调用
    val isCall = function("1", "2", "3")
}

通过 show Java 查看

public final void function(@NotNull String... rarg) {
   Intrinsics.checkNotNullParameter(rarg, "rarg");
   String var2 = "Function 函数~ 接受到参数  rarg 长度:" + rarg.length + "  ";
   boolean var3 = false;
   System.out.println(var2);
}

函数嵌套

Kotlin中可以函数嵌套定义函数,这是一个非常重要的特性,在JAVA中不可能实现的

/**
 * 定义函数
 */
fun function(message: String) {
    println("function")

    fun test(code: Int) {
        println("test code:${code}")
    }

    println(message)
    test(200)

}

@Test
fun main() {
    //调用
    val isCall = function("一个参数Mesage")

}

打印:

function
一个参数Mesage
test code:200

先看看编译器做了什么?

public final void function(@NotNull String message) {
   Intrinsics.checkNotNullParameter(message, "message");
   String var2 = "function";
   boolean var3 = false;
   System.out.println(var2);
    $fun$test$1 = null.INSTANCE;  //函数为静态对象
   var3 = false;
   System.out.println(message);
   $fun$test$1.invoke(200);   //通过invoke函数调用
}

函数内部函数的定义:

$fun$test$1 = null.INSTANCE;

函数内部的调用:

$fun$test$1.invoke(200);

可以看出编译器会将函数内部函数,编译生成一个实现内,FunctionN类,并且有一个重写incoke方法,创建一个静态对象,然后invoke方法就是嵌套函数的实现,在Lambda表达式函数编程函数当参数传递DSL都与函数嵌套有关。

public interface Function

out R :表示泛型

可以看到 ***$1 代表Function1 继承interface Function Function 接口,在Kotlin一个有Functions.kt都是定义23个新接口,从0~22

package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0 : Function {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1 : Function {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2 : Function {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2): R
}

//.....省略

/** A function that takes 22 arguments. */
public interface Function22 : Function {
    /** Invokes the function with the specified arguments. */
    public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
}

可以看到 out R, 最后一个参数进行返回值的类型,如果没有用Unit代替

函数当参数传递

假设一个函数当参数传递应该怎么办?首先就应该想到C、C++中的指针(指正函数),把函数当成指针,获取到指针所存在的位置,把这个指针当成变量传入其他函数的变量即可

Kotlin可以使用::关键词取出fun的函数指针

/**
 * 定义一个函数
 * 这里用类一个缩写,只要函数只有执行一句代码,就可以这样写
 */
fun funPrint(msg: String) = println(msg)

/**
 * 定义函数
 * funParameter: Function1【具体的函数】 为该函数的参数
 */
fun functionTest(message: String, funParameter: Function1) {

    funParameter(message) //通过 Function1 传参默认调用,也会默认调用 invoke

    funParameter.invoke(message) //通过invoke调用

}

@Test
fun main() {
    //通过  ::+函数名 获取地址, 这是没有传参
    val funAddress = ::funPrint

    functionTest("this Message", funAddress)

}

看看编译后的代码:

public final void funPrint(@NotNull String msg) {
   Intrinsics.checkNotNullParameter(msg, "msg");
   boolean var2 = false;
   System.out.println(msg);
}

public final void functionTest(@NotNull String message, @NotNull Function1 funParameter) {
   Intrinsics.checkNotNullParameter(message, "message");
   Intrinsics.checkNotNullParameter(funParameter, "funParameter");
   funParameter.invoke(message);
   funParameter.invoke(message);
}

@Test
public final void main() {
   KFunction funAddress = new Function1((ExampleUnitTest)this) {
      // $FF: synthetic method
      // $FF: bridge method
      public Object invoke(Object var1) {
         this.invoke((String)var1);
         return Unit.INSTANCE;
      }

      public final void invoke(@NotNull String p1) {
         Intrinsics.checkNotNullParameter(p1, "p1");
         ((ExampleUnitTest)this.receiver).funPrint(p1);
      }
   };
   this.functionTest("this Message", (Function1)funAddress);
}
  • 如果当参数其实都是定义 FunctionN接口
  • 具体函数用invoke(vararg...)
  • ::funPrint函数名 通过接口FuncationN实现,获取实体对象,在invoke函数调用函数指针

Unit

可以理解Unit 与 Java中的void类似,当一个函数没有返回值的时候,可以用Unit代替,也可以省略,编译器会隐式的加上去

你可能感兴趣的:(Kotlin 函数)