函数
Kotlin中函数的声明格式
`fun nameOfFunction(parament1:Type, parament2:Type = default):returnType {body}`
函数的参数可以有默认值,有多个参数时时当有默认值参数在无默认值参数之前就要通过具体的参数名来调用函数如 ```kotlin fun foo( bar: Int = 0, baz: Int, ) { /……/ }
foo(baz = 1) // 使用默认值 bar = 0
- 当一个方法要覆盖一个有默认值的方法时它不可以带默认值
```kotlin
open class A {
open fun foo(i: Int = 10) { /*……*/ }
}
class B : A() {
override fun foo(i: Int) { /*……*/ } // 不能有默认值
}
- 如果默认参数之后的最后一个参数是Lambda,那么它既可以作为具名参数在括号内传入,也可以在括号外传入 ```kotlin fun foo( bar: Int = 0, baz: Int = 1, qux: () -> Unit, ) { /……/ }
foo(1) { println(“hello”) } // 使用默认值 baz = 1 foo(qux = { println(“hello”) }) // 使用两个默认值 bar = 0 与 baz = 1 foo { println(“hello”) } // 使用两个默认值 bar = 0 与 baz = 1
- 可变量的参数,函数的参数可以用vararg修饰符标记,它允许将可变参数传递给函数
```kotlin
fun <T> asList(vararg ts:T): List<T> {
val rsult = ArrayList<T>()
for(t in ts)
result.add(t)
return result
}
val list = asList(1,2,3)
//如果vararg参数不是列表中的最后一个参数可使用具名参数语法传递其后的参数值,如下
val a = arrayOf(1,2,3)
val list = asList(-1,0,*a,4) //伸展操作符
函数也可以作为类型来传递,函数类型的实例调用如下。带与不带接收者的函数类型非字面值可以互换,接收者可以代替第一个参数反之亦然,如(A,B)-> C类型的值可以传给或赋值给需要A.(B) -> C的地方 ```kotlin fun main() { val stringPlus: (String, String) -> String = String::plus val intPlus: Int.(Int) -> Int = Int::plus
println(stringPlus.invoke(“<-“, “->”)) println(stringPlus(“Hello, “, “world!”))
println(intPlus.invoke(1, 1)) println(intPlus(1, 2)) println(2.intPlus(3)) // 类扩展调用
}
- ** Lambda表达式**
- 类型别名,可以给属性函数或者类等起类型别名
```kotlin
typelias FileTable<K> = MutableMap<K, MutableList<File>>
typelias MyHander = (Int, String, Any) -> Unit
class A {
inner class Inner
}
class B {
inner class Inner
}
typealias AInner = A.Inner
typealias BInner = B.Inner
- Lambda表达式是一种函数字面值,下面的函数是一个高阶函数,接受的第二个参数是一个表达式,和都二行的具名函数是等价的 ```kotlin max(strings, { a, b -> a.length < b.length })
fun compare(a: String, b: String): Boolean = a.length < b.length
- Lambda的完整语法形式如下,当函数的最后一个参数是函数时作为参数传入的Lambda表达式可在圆括号之外,从Lambda表达式返回值时,如果没有显式的返回默认隐式返回最后一个表达式
```kotlin
val sum: (Int, Int) -> Int = {x:Int, y:Int -> x+y }
//下面的Lambda表达式放在了圆括号之外
val product = items.fold(1) {acc, e -> acc*e}
//Lambda表达式是唯一的调用参数时圆括号就可以省略
run {print("...")}
- 内联函数
- 使用内联函数可以减少开销,下面的高阶函数反编译后得到的JAVA代码 ```kotlin fun Num1AndNum2(Num1: Int, Num2:Int, operation: (Int, Int) -> Int) { return operation(Num1, Num2) } fun main() { val result = Num1AndNum2(1,2) { n1, n2 -> n1 + n2 } println(result) }
//反编译的JAVA代码简化后,主要是定义一个Function类并调用Function的invoke函数来实现 //下面是内联函数 inline fun Num1AndNum2(Num1: Int, Num2:Int, operation: (Int, Int) -> Int) { val result = operation(Num1, Num2) return result }
- 上述的函数我们使用inline关键字后,Kotlin编译器就会在编译时把内联函数的代码自动替换到调用它的地方。这样在一些循环结构里面,就不会像之前一样每次都创建一个Function类增加开销了, 具体流程如下
```kotlin
//代码执行时会把Lambda表达式的代码替换到函数类型参数调用的地方,
//然后用整合好的内联函数中的代码用到函数调用的地方
//调整后代码如下
fun main() {
val result = 1+2
println(result)
}
可以使用noinline禁用内联,如下代码所示,block1是内联block2是非内联,用非内联的原因主要是内联 函数的参数只能传给另一个内联函数。
inline fun (block1: () -> Unit, noinline block2: () -> Unit)内联函数中引用的Lambda表达式是可以用return关键字来返回的,而非内联的只能局部返回 ```kotlin //局部返回 fun printString(str:String, block: (String) -> Unit) { println(“printString begin”) block(str) println(“printString end”) }
fun main() { println(“main start”) val str = “” printString(str) { s -> println(“lambda start”) if(s.isEmpty()) return @printString println(s) println(“lambda end”) } println(“main end”) } main start printString begin lambda start //内联函数的返回 inline fun printString(str:String, block: (String) -> Unit) { println(“printString begin”) block(str) println(“printString end”) }
fun main() { println(“main start”) val str = “” printString(str) { s -> println(“lambda start”) if(s.isEmpty()) return println(s) println(“lambda end”) } println(“main end”) } main start printString begin lambda start printString end main end ```
