1、函数
函数(方法)使用fun关键字来定义
fun test(param: String) {
}
fun test(x: Int, y: Int) : Int {
return x + y
}
使用等式替代括号
fun test(x: Int, y: Int): Int = x + y
如何写默认值
fun test(x: Int, y: Int = 4): Int = x +y
当你这么写的时候,表示你调用该方法,第二个参数是可选的
test(1)的结果是5
test(1, 2)的结果是3
2、Infix
先看写法:
infix fun Int.plus(x: Int): Int {
return this + x
}
调用的时候,你可以写1.plus(2),也可以利用infix的特性写成1 plus 2
使用infix需要注意几点:
- 成员函数或者扩展函数
- 单入参函数
- 关键字infix
3、Parameters
Kotlin中的函数参数写法都是 name:Type,并且可以在括号中赋初始值。有趣的是,如果你不想传递没有必要的参数,在赋初始值后,你可以不传递。
4、有返回值
funprintHello(name:String?):Unit {
if(name!= null)
println("Hello ${name}”)
else
println("Hi there!”)
// `return Unit` or `return` is optional
}
fun double(x:Int):Int = x * 2
5、Varargs数量可变的入参
fun <T> asList(test: String,vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts)// ts is an Array
result.add(t)
return result
}
一个函数的入参,最后一个,可以标记varargs,允许可变数量的入参。asList(1, 2, 3)
6、函数的范围
Kotlin中的函数可以写在文件的顶级,也就是说可以在不创建类的情况下去调用方法。也可以作为本地的函数。
Kotlin支持函数嵌套
funtest1() {
fun test2() {
}
test2()
}
当然还有类的成员函数,需要创建类才能调用。
7、范型函数
函数可以有范型参数。
8、Inline函数
使用高阶函数会带来一些运行时的坏处:每个函数是一个对象,捕获闭包(captures a closure),函数体里面的变量都可以被调用。内存分配(函数对象和类)以及虚拟调用(virtual calls)会引入运行时间开销。
但是,看起来再许多案例中,这种开销通过内联化lambda表达式能够被完全避免。
考虑下面的情况:
lock(l) { foo() }
编译器没有为参数创建一个函数对象并生成一个调用。取而代之,编译器可以生成以下代码:
l.lock()
try {
foo()
}
finally {
l.unlock()
}
这个不是我们从一开始就想要的吗?
为了让编译器这么做,我们需要使用 inline 修饰符标记 lock()函数:
inline fun lock<T>(lock: Lock, body: () -> T): T {
// ……
}
inline 修饰符影响函数本身和传给它的 lambda 表达式:所有这些都将内联到调用处。
在java中我们不能直接去申明内联函数,因此这个概念比较模糊。内联可能导致生成的代码增加,但是如果我们使用得当(不内联大函数),它将在性能上有所提升,尤其是在循环中的“超多态(megamorphic)”调用处。
如果你只想被(作为参数)传给一个内敛函数的lambda表达式中有一些被内联,你可以用noinline修饰符标记一些函数参数。可以内联的lambda表达式只能在内联函数内部调用或者作为可内联的参数传递,但是noinline可以以任何方式操作,比如存储在字段中,传送等。
⚠️如果一个内联函数没有可内联的函数参数,并且没有具体化的类型参数,编译器会产生警告,因为内联这样的函数很可能没有益处。
9、扩展函数
参考Anko
10、Higher-Order Functions and Lambdas
高阶函数可以将函数作为入参,或者作为返回值。
fun<T> lock(lock: String, body: () ->T):T {
lock.toString()
return body()
}
valresult = lock("lock", ::toBeSynchronized)
val result1 =lock("lock", { test1()})
valresult2 = lock("lock"){ test1()}
使用it关键字,当函数只有一个入参的时候,可以这么用。了解下map()这个高阶函数
list.map{ x -> x +2 }
list.map{ it * 2}
list.map{ if (it /2 == 0) (it *2)else (it +2)}
11、Tail recursive functions
尾递归函数,在函数前面加上tailrec修饰符,允许用循环写的算法改用递归函数,而没有堆栈溢出的风险。并且相比传统的写法更加的简单。
tailrec funfindFixPoint(x: Double = 1.0): Double
=if (x == Math.cos(x)) x elsefindFixPoint(Math.cos(x))
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if (x == y) return y
x = y
}
}