函数:
1、函数申明
Kotlin 中的函数使用 fun 关键字声明。如:
fun double(x: Int): Int {
return 2 * x
}
2、函数默认值
●函数的参数可以有默认值
fun read(b: Array, off: Int = 0, len: Int = b.size) {
……
}
默认值通过类型后面的 = 给出的值来定义。
●重写的方法,与基类的方法有相同的默认值,重写时,不能再次定义默认值。如:
open class A {
open fun foo(i: Int = 10) { …… }
}
class B : A() {
override fun foo(i: Int) { …… } // 不能有默认值
}
●当一个函数有多个默认参数时,我们可以通过命名参数来调用该函数。如:
fun foo(bar: Int = 0, baz: Int) { …… }
foo(baz = 1) // 使用默认值 bar = 0
函数:
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
……
}
// 使用命名参数调用:
reformat(str,
normalizeCase = true,
upperCaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = '_'
)
●当一个函数调用混用位置参数与命名参数时,所有位置参数都要放在第一个命名参数之前。例如
允许调用 f(1, y = 2)
但不允许 f(x = 1, 2)
●可以通过使用星号操作符将可变数量参数(vararg) 以命名形式传入:
fun foo(vararg strings: String) { …… }
foo(strings = *arrayOf("a", "b", "c"))
注意,在调用 Java 函数时不能使用命名参数语法,因为 Java 字节码并不总是保留函数参数的名称
3、函数返回值
如果一个函数不返回任何有用的值,它的返回类型是 Unit。Unit 是一种只有一个值——Unit 的类型。这个值不需要显式返回。与java中的void类似。
如:
fun printHello(name: String?): Unit {
if (name != null)
println("Hello ${name}")
else
println("Hi there!")
// `return Unit` 或者 `return` 是可选的
}
上面函数等同于
fun printHello(name: String?) { …… }
4、单函数表达式
当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可
fun double(x: Int): Int = x * 2
该函数的返回值类型可由编译器推断,显式声明返回的类型是可选的。可写成
fun double(x: Int) = x * 2
5、可变数量的参数:
●函数的参数(通常是最后一个)可以用 vararg 修饰符标记
fun asList(vararg ts: T): List {
val result = ArrayList()
for (t in ts) // ts is an Array
result.add(t)
return result
}
// 传参时
val list = asList(1, 2, 3)
●在函数内部,类型 T 的 vararg 参数的可见方式是作为 T 数组,即上例中的 ts 变量具有类型 Array < out T>。
●只有一个参数可以标注为 vararg。如果 vararg 参数不是列表中的最后一个参数, 可以使用命名参数语法传递其后的参数的值,或者,如果参数具有函数类型,则通过在括号外部传一个 lambda。
●当我们调用 vararg-函数时,我们可以一个接一个地传参,例如 asList(1, 2, 3),或者,如果我们已经有一个数组并希望将其内容传给该函数,我们使用伸展(spread)操作符(在数组前面加 *)如:
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
6、中缀表示法
标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。中缀函数必须满足以下要求:
▲它们必须是成员函数或扩展函数;
▲它们必须只有一个参数;
▲其参数不得接受可变数量的参数且不能有默认值
如:
infix fun Int.shl(x: Int): Int { …… }
// 用中缀表示法调用该函数
1 shl 2
// 等同于这样
1.shl(2)
注意,中缀函数总是要求指定接收者与参数。当使用中缀表示法在当前接收者上调用方法时,需要显式使用 this;不能像常规方法调用那样省略。这是确保非模糊解析所必需的
class MyStringCollection {
infix fun add(s: String) { …… }
fun build() {
this add "abc" // 正确
add("abc") // 正确
add "abc" // 错误:必须指定接收者
}
}
7、函数作用域
在 Kotlin 中函数可以在文件顶层声明,这意味着你不需要像一些语言如 Java、C# 或 Scala 那样需要创建一个类来保存一个函数。此外除了顶层函数,Kotlin 中函数也可以声明在局部作用域、作为成员函数以及扩展函数
●局部函数
一个函数在另一个函数内部
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
局部函数可以访问外部函数(即闭包)的局部变量,所以在上例中,visited 可以是局部变量
fun dfs(graph: Graph) {
val visited = HashSet()
fun dfs(current: Vertex) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v)
}
dfs(graph.vertices[0])
}
●成员函数
成员函数是在类或对象内部定义的函数
class Sample() {
fun foo() { print("Foo") }
}
●泛型函数
函数可以有泛型参数,通过在函数名前使用尖括号指定
fun singletonList(item: T): List { …… }
Lambda表达式
在java8.0以后开始支持Lambda表达式的写法。Kotlin中的Lambda与java中的Lambda相同。
语法三种形式:
无参数的情况 :
val/var 变量名 = { 操作的代码 }
有参数的情况
val/var 变量名 : (参数的类型,参数类型,…) -> 返回值类型 = {
参数1,参数2,… -> 操作参数的代码
}
可等价于
// 此种写法:即表达式的返回值类型会根据操作的代码自推导出来。
val/var 变量名 = { 参数1 : 类型,参数2 : 类型, … -> 操作参数的代码 }
lambda表达式作为函数中的参数的时候,这里举一个例子:
fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, … ) -> 表达式返回类型){
…
}
举例说明:
// 无参的时候
// 常规代码
fun test(){
println("无参数")
}
// lambda代码
val test = {
println("无参数")
}
有参的时候
// 常规代码
fun test(a : Int , b : Int) : Int{
return a + b
}
// lambda
val test : (Int , Int) -> Int = {
a , b -> a + b
}
// 或者
val test = {
a : Int , b : Int -> a + b
}
// Lambda表达式作为函数中的参数的时候
// 常规代码
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
// 调用
test(10,sum(3,5)) // 结果为:18
// lambda
fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
// 调用
test(10,{
num1: Int, num2: Int -> num1 + num2
})
// 结果为:18
说明:
invoke()函数:表示为通过函数变量调用自身,因为上面例子中的变量b是一个匿名函数
这里以Android中常见的按钮点击事件监听为例:
Kotlin写法:
mBtn.setOnClickListener(object: View.OnClickListener{
override fun onClick(v: View?) {
Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show()
}
})
使用Lambda表达式等同于
mBtn.setOnClickListener {
Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show()
}
Lambda表达式的特点:
◆ Lambda表达式总是被大括号括着
◆ 其参数(如果存在)在 -> 之前声明(参数类型可以省略)
◆ 函数体(如果存在)在 -> 后面。
Kotlin语言约定Lambda表达式的参数只有一个的时候可以使用it来使用此参数。it可表示为单个参数的隐式名称
fun test(num1 : Int, bool : (Int) -> Boolean) : Int{
return if (bool(num1)){
num1
} else{
0
}
}
println(test(10,{it > 5}))
println(test(4,{it > 5}))
// 输出结果为:
// 10
// 0
下划线的使用
在使用Lambda表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数。
例子:
val map = mapOf("key1" to "value1","key2" to "value2","key3" to "value3")
map.forEach{
key , value -> println("$key \t $value")
}
// 不需要key的时候
map.forEach{
_ , value -> println("$value")
}
/*输出结果:
key1 value1
key2 value2
key3 value3
value1
value2
value3*/
闭包
说闭包前,我们先说一下作用域的问题。
我们知道变量的作用域,通常是两种:全局变量与局部变量
var n = 999
fun f1() {
println(n) // 打印999
}
f1()
当我们调用f1函数的时候,会正确输出999,从而得知,在函数内部可以直接读取全局变量,如果想要从函数外部读取函数内的变量呢?我们知道这是无法读取的。
fun f1(){
var n=999
}
// println(n) // 报错!!! n是函数内局部变量,外部无法调用
那么,如何在外部调取局部的变量呢?
答案就是——闭包
闭包就是能够读取其他函数内部变量的函数。
作用
● 一个是前面提到的可以读取函数内部的变量
● 另一个就是让这些变量的值始终保持在内存中
举例说明:
fun test(b : Int): () -> Int{
var a = 3
return fun() : Int{
a++
return a + b
}
}
val t = test(3)
println(t())
println(t())
println(t())
// 输出结果:
7
8
9
说明:
闭包就是在函数被创建的时候,存在的一个私有作用域,并且能够访问所有的父级作用域。每个功能模块我们都能够拆解到不同fun里,不同fun里的变量保持相互调用的可能性,相互独立还彼此不影响。
广义上来说,在Kotlin语言之中,函数、条件语句、控制流语句、花括号逻辑块、Lambda表达式都可以称之为闭包,但通常情况下,我们所指的闭包都是在说Lambda表达式。
自执行闭包
自执行闭包就是在定义闭包的同时直接执行闭包,一般用于初始化上下文环境。 例如:
{ x: Int, y: Int ->
println("${x + y}")
}(1, 3)
参考自:http://www.cnblogs.com/Jetictors/p/8647888.html