Kotlin快速入门(2) -- 函数

来源:互联网 发布:手机时钟同步软件 编辑:程序博客网 时间:2024/05/21 13:54

可以毫不夸张地说,在Kotlin的世界里,函数是第一公民,这些函数的特性大大简化了我们编写业务逻辑的代码量。

1.扩展函数

Kotlin 也提供了一种可以在不继承父类,也不使用类似装饰器这样的设计模式的情况下对指定类进行扩展。这就是使用扩展函数:
声明扩展函数的时候,只需要在函数名前面加上被扩展的类名即可。例如,我们可以给Context类添加一个toast()的扩展函数,之后在任何继承了Context这个抽象类的方法中都可以直接使用我们自己写的toast()

fun Context.toast(content : String, time : Int = 1000){    Toast.makeText(this,content,time).show()}

在Activity中就可以这么用:

class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        toast("Hello World!")    }}

是不是感觉爽爆了,这样以来,很多操作都可以被简化了。

2.高阶函数

高阶函数就是可以接受函数作为参数或者返回一个函数的函数。
传递无参函数:

fun main(args: Array<String>) {    say({ speak() })    say { speak() }//当只有一个函数作为参数的时候,可以省略小括号}//say() 函数的参数为一个函数,它的名字是:greet,返回值为Unit,无参数fun say(greet: () -> Unit) {    greet()}fun speak() {    println("Hello world")}

结果是:

Hello worldHello world

这里的() -> Unit表示的是一个函数类型。

传递有参函数:

fun max(collection: Collection<Int>, less: (Int, Int) -> Boolean): Int? {    var max: Int? = null    for (it in collection)        if (max == null || less(it,max!!))            max = it    return max}fun compare(a: Int, b: Int): Boolean = a > b

调用:

println(max(arrayListOf(1, 2, 3, 4), ::compare))

或者直接传入一个Lambda表达式的字面函数

println( max(arrayListOf(1,2,3,4),{ a, b -> a > b }))

结果是:

4

需要说明的是
Kotlin 中::表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个函数。

3.闭包

闭包可是个好玩的东西,由于Java8以前没有闭包这个概念,平时写Android也没怎么遇到,所以就一直没去了解。我去问了一下隔壁做前端的兄弟,他告诉我JS里面的闭包是:

闭包是就是一个函数的返回值也是函数,并且返回的函数里面还引用了外部函数的变量

听得我是雨里雾里,去Google了一下发现大家对这个概念的解释众说纷纭,虽然还是不明白,但是大概知道了这就一个“词法的作用域问题”,最后有幸在知乎上看到了这篇文章「JS 中的闭包是什么?,才豁然开朗。换个角度看,原来以前在写JS的时候自己都不自觉地用到了闭包,这才是它的魅力所在–更符合自然的语言词法作用域。Kotlin是支持闭包的,这让我一下子对它的好感度倍增。
来看一段官方文档中闭包的代码吧:

var sum = 0ints.filter{it > 0}.forEach {    sum += it}print(sum)

forEach()这个函数中访问到了作用域以外的sum从我们直观看来,这是理所当然的,但是就确实使用到了闭包,闭包就是这么神奇的一个东西。

4.内联函数

概念

就内联函数这一点,可能是自己的理解能力有限,起初看官方文档看的不是很懂,后来看到维基百科对这个概念解释得非常详细,原来是这么简单的一个东西,一下是引用维基百科的解释:

在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展);也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。但在选择使用内联函数时,必须在程序占用空间和程序执行效率之间进行权衡,因为过多的比较复杂的函数进行内联扩展将带来很大的存储资源开支。另外还需要非常注意的是对递归函数的内联扩展可能带来部分编译器的无穷编译。

内联函数的语法格式就是定义函数的时候fun前面添加inline,如:

/** * Performs the given [action] on each element. */@kotlin.internal.HidesMemberspublic inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {    for (element in this) action(element)}

又见到了熟悉的forEach()这个函数,如果调用的时候这样写的:

list.forEach{    printf("Hello")}

那么在编译的时候,会自动变成这样:

for(element in this)printf("Hello")  

从而节省了每次调用函数带来的额外时间开支。值得注意的是,如果把非高阶函数定义成内联函数,这对性能几乎没有实质的提升。所以内联函数最好用来定义高阶函数

reified关键字

“reified” 是“具体的”的意思,Kotlin 中这个关键字用来修饰泛型内联函数的类型参数(<reified T>),了它修饰之后,就可以拿到T类型的Class了,例如在Android中可以给Activity添加一个startActivity ()的扩展内联函数,用以简化跳转Activity的操作:

inline fun <reified T> Activity.startActivity(){    startActivity(Intent(this,T::class.java))}

然后就可以在Activty中这样去跳转:

startActivity<SecondActivity>()

又是一个骚操作。

5.字面函数(function literal)

匿名函数或Lambda达式就是一个 “字面函数”,也就是没有声明的函数,但立即作为表达式传递下去,如:

max(arrayListOf(1,2,3,4), {a, b -> a.length < b.length })

max显然的第二个参数是一个函数,它就可以叫做一个字面函数或Lambda表达式。
但如果事先声明了,就不是字面函数了:

fun compare(a: Int, b: Int) : Boolean = a < b max(arrayListOf(1,2,3,4),::compare)

6.Lambda表达式语法(Lambda Expression Syntax)

我看译者把“Lambda Expression Syntax”翻译过来的是一个叫“函数文本语法”的东西(总感觉这里翻译得怪怪的,直译过来应该是“Lambda表达式语法”),我的理解是一个Lambda表达式(即一个函数)可以直接赋值给一个变量,这可以让传递字面函数的语义更加明确。如:

var compare = {a : Int,b : Int -> a>b}

就可以这样调用:

max(arrayListOf(1,2,3,4),::compare)

函数文本有时只有一个参数。如果kotlin可以从它本生计算出签名,那么可以省略这个唯一的参数,并会通过it隐式地声明它:

ints.filter {it > 0}//这是 (it: Int) -> Boolean  的字面意思

至于函数签名这个东西,还是引用维基百科的解释吧:

In computer science, a type signature or type annotation defines the inputs and outputs for a function, subroutine or method. A type signature includes the number of arguments, the types of arguments and the order of the arguments contained by a function. A type signature is typically used during overload resolution for choosing the correct definition of a function to be called among many overloaded forms.

7.匿名函数(Anonymous Functions)

真是有毒,不知道为何我参考的中文档会把“Anonymous Functions”翻译成“函数表达式”,在JS中确实有“函数表达式”这个概念,但是人家是由“Function Expression”翻译而来的。(两者的形式确实有几分相似,这个问题暂且放一放,我之后再去研究)

匿名函数和普通函数的区别就是没有了函数名字,如下面这种形式:

fun(x: Int, y: Int): Int = x + y

或:

fun(x: Int, y: Int): Int {    return x + y}

需要注意的是,匿名函数的返回值也是可以被编译器自动推导出来的。

参考资料:

https://huanglizhuo.gitbooks.io/kotlin-in-chinese/FunctionsAndLambdas/Higher-OrderFunctionsAndLambdas.html
http://kotlinlang.org/docs/reference/lambdas.html

原创粉丝点击