Kotlin 函数

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);
   <undefinedtype> $fun$test$1 = null.INSTANCE;  //函数为静态对象
   var3 = false;
   System.out.println(message);
   $fun$test$1.invoke(200);   //通过invoke函数调用
}

函数内部函数的定义:

<undefinedtype> $fun$test$1 = null.INSTANCE;

函数内部的调用:

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

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

public interface Function<out R>

out R :表示泛型

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

package kotlin.jvm.functions

/** A function that takes 0 arguments. */
public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}
/** A function that takes 1 argument. */
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
    /** 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<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : Function<R> {
    /** 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<String, Unit>【具体的函数】 为该函数的参数
 */
fun functionTest(message: String, funParameter: Function1<String, Unit>) {

    funParameter(message) //通过 Function1<String, Unit> 传参默认调用,也会默认调用 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代替,也可以省略,编译器会隐式的加上去

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 一、 概述 函数:也就是子程序。高阶函数:在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:接受一个或多...
    进击的小强阅读 851评论 1 50
  • 函数的定义及使用 函数function,kotlin中使用fun定义一个函数 fun square(r: Doub...
    pianoboyfans阅读 678评论 1 1
  • 可以到掘金,效果更好聊一聊Kotlin函数 一直想学习下Kotlin,毕竟已经被Android官方宣布kotln ...
    juexingzhe阅读 715评论 0 2
  • kotlin函数 本文主要介绍Kotlin函数的基础使用和常见用法,大部分内容来自官方文档,也包含个人理解内容,将...
    小神之路阅读 571评论 0 0
  • 定义函数Kotlin定义一个函数的风格大致如下 访问控制符 fun 方法名(参数,参数,参数) : 返回值类型{....
    IT小魔女的故事阅读 541评论 2 1