转载

Koltin第七讲---函数定义

内容简介

个人认为 Kotlin 函数的设计属于改动最多,也最为惊艳的。尤其是函数可以以参数形式传递,为后续带来了更多的发挥空间。以及巧妙的运用 Lambda (其实就是个对象)表达式,将 Java 中的很多不可能变成了可能。接下来我们来揭开函数的面纱。

函数定义

我们要如何定义函数呢?在  Kotlin  中函数定义,不再和  Java  一样。而是通过  fun  修饰符修饰。并且定义过程中有很多的新的功能。

简单的定义函数&调用

函数定义行参&返回值

定义一个函数,若需要行参使用  fun函数昵称(行参1:类型,行参2:类型)  声明即可。 若需要返回值要在函数后方增加  :返回类型  即可。

函数默认参数

记得类的定义讲过的默认值功能吗? 我们定义的主构造方法的时候,可以为成员变量添加默认值。   Kotlin  中也可以为函数的行参增加默认值。

补充一点,函数默认值功能只能在 Kotlin 中使用,若  Java 调用  Kotlin 是无效的(老老实实传参吧)。

可变参数

在  Java  中也具有可变参数,只需要在定义行参的时候,使用  类型...变量昵称  定义即可(本质是数组)。

在  Kotlin  也具有可变参数,只需要对行参通过  vararg  修饰即可。

接下来我们看看  Kotlin  中可变参数的本质是什么东东。 我尝试传入数组能成功吗? 经过本人尝试,我分别传了数组&集合都在编译器就直接报错了,奇怪难道  Kotlin  的可变参数本质难道不是数组?

我尝试用  Java  的代码调用  Kotlin  的可变参数方法,发现可以调用成功,并且查看了反编译后的代码,发现本质还是数组。

上面的问题一直困扰我很久,由于这个可变参数用处不多,我也就没有在意。 直到有一天我用  Kotlin  编写动态代理的时候,遇到了这样的问题。

请看下方代码:

报错内容:

我尝试看了下  method?.invoke(this,args)  的  invoke  方法第二个参数的确是可变参数,我传入的是  Kotlin  的数组类型,最终报错了。

最终找到了问题  Kotlin  中对可变数组的类型限制还是挺严格的,虽然本质上它是数组,但是  Kotlin  就是不让你直接传递数组(应该是为了代码上的歧义吧)。 我们只需要在数组的前面加入一个  *  即可,将数组变成可变数组。

具名参数

前面讲了 可变参数 与  函数默认参数 ,其实也是为具名参数做了铺垫。

回想下在  Java 中的可变参数,有一个硬性规定可变参数只能定义在最后一个(想想也是,不然怎么区分哪些参数属于可变的)。在  Kotlin 中也有这种问题,并且默认函数默认值也会出现这种问题,例如我将函数的中间的一个参数定义成有默认值的,当使用中间函数的默认值功能,就不知道该如何传值了。

为了解决这个问题  Kotlin 提供了一种具名参数的功能,我们只需要在传参的时候,使用  参数昵称=参数值 即可。

函数嵌套

看完上面的内容,我想大家应该可以定义一些  Kotlin  的函数了吧。接下来我们来看看  Kotlin  比较重要的特性以及原理。在  Kotlin  中可以函数中嵌套定义函数,在  Java  中这是不可能实现的。

啥原理呢? 其实在编译器编译的时候,会将函数的内部函数。 编译生成一个实现  FunctionN  类,并且有一个重写了  invoke  方法,创建了一个静态对象,然后  invoke  方法就是嵌套函数的实现。

别小看这一改动,这一改动是  Kotlin  中函数的精髓,  Kotlin  的  Lambda  表达式丶函数式编程丶函数以参数传递,以及后续的  DSL  都和这个有一定关系。

反编译源码:

DemoKt$test$1源码:

这里讲到一个 FunctionN ,当且大家就需要知道是一个接口,接口中定义了一个方法  invoke 。后续的  Lambda 会详细讲解

函数当参数传递

在  C  &  C++  中有函数指针的概念,由于  Java  中去除了复杂的指针的概念,因此  Java  中我们的定义的函数不可以以参数传递的,只能出传递对象(所有的  CallBack  回调都是这样的形式)。

Kotlin  中没有这种约束,如果要传递一个定义好的  fun  函数,可以通过  ::  关键词,就能取  fun  函数的函数指针(函数指针,我是这么叫的啦,嘿嘿! ),这个其实在高阶函数中经常使用。

接下来我们用 Java 的角度分析下,是如何实现的呢?

我们定义  funCall 方法的第二个参数类型是  Function1 它本质是一个接口,在后续的  Lambda 中会详细讲解这里接口。我们先来看看  main 方法。

通过上面分析可知,其实将函数变为参数传递,本质是新生成了一个实现  FunctionN  的类,并且重写了  invoke  方法。 而  invoke  的函数体做的就是传入函数的函数调用。 (是不是和函数嵌套有一些类似啊? 只是函数体不同) 所以本质上函数嵌套与函数参数传递,都是传递了一个实现  FunctionN  对象(后续的  Lambda )也是一样的哦。

推荐阅读

Koltin第七讲---函数定义

Koltin第七讲---函数定义 --END--

识别二维码,关注我们

Koltin第七讲---函数定义

原文  http://mp.weixin.qq.com/s?__biz=MzUyODg5NDg3NQ==&mid=2247484066&idx=1&sn=571fc0602ac32963bc51dcd82493bb89
正文到此结束
Loading...