val和var
var表示普通的变量;val表示只读变量,即var+final(引用不可变)。
尽可能采用val声明变量。
类型声名
- 声明变量类型
类型名放在变量名后面,比如var a:Int = 100,val b:String = "a string",因为Kotlin中有类型推导的语言特性,所以也可以让编译器在不显式声明类型的情况下,自动推导出所需的类型,因此还可以这样声明变量var a = 100,val b = "a string"。 - 声明函数返回值类型
函数的返回值类型放在函数名后,比如fun returnParam(param: Int): Int { return param },这种函数中的函数体在{}块之间;还有一种是函数的定义可以通过单行表达式与等号来实现,比如fun returnParam(param: Int) = param,此时可以不声明返回值类型。如果以普通方式定义函数,如果省略了返回值类型,那么默认返回Unit类型。
递归函数不能省略返回值类型。
高阶函数与Lambda表达式
函数式语言的典型特征——函数是头等公民,可以像类一样在顶层直接定义函数,可以在函数内部定义局部函数,可以直接将函数传递给另一个函数,可以在其它函数内被返回。Kotlin支持部分函数式特性。
高阶函数是一种更加高级的抽象机制,它是以其它函数作为参数或返回值的函数。
- 函数的类型
格式:(参数类型)->返回值类型,如果没有参数,那么参数部分直接用()表示,返回值类型为Unit也必须声明。例如(Int, String) -> String,() -> Int。 - 函数和变量的引用,通过::实现。
- 匿名函数
// 例 1 当一个函数作为参数时
fun main() {
paramsHaveFun(666, ::printNum)
}
fun printNum(num: Int) {
print(num)
}
fun paramsHaveFun(num: Int, param: (Int) -> Unit) {
println("这是一个参数为函数类型的函数")
param(num)
}
// 运行结果
这是一个参数为函数类型的函数
666
// 例 2 当fun printNum不需要复用时,可以使用匿名函数,此时函数名要缺省
fun main() {
paramsHaveFun(666, fun(num: Int) {
println("作为参数且不需复用时,缺省函数名")
println(num)
})
}
fun paramsHaveFun(num: Int, param: (Int) -> Unit) {
println("这是一个参数为函数类型的函数")
param(num)
}
// 运行结果
这是一个参数为函数类型的函数
作为参数且不需复用时,缺省函数名
666
- Lambda表达式(变量形式)
格式: val 变量名: (函数类型) = {参数部分->返回值}
4.1 Lambda表达式必须通过{}包裹
4.2 Lambda变量声明函数类型,那么Lambda的参数部分类型可以省略
4.3 Lambda声明了参数部分类型,返回值支持类型推导,那么Lambda变量可以省略函数类型声明
4.4 Lambda表达式返回的不是Unit,那么返回值类型默认为最后一行表达式的值类型
// 例 1 Lambda定义变量,既声明函数类型,也声明参数类型
val test: (Int) -> Unit = { x: Int -> println("这是lambda表达式,$x") }
// 例 2 Lambda定义变量,只声明函数类型
val test: (Int) -> Unit = { x -> println("这是lambda表达式,$x") }
// 例 3 Lambda定义变量,只声明参数部分类型
val test = { x: Int -> println("这是lambda表达式,$x") }
// 使用
test(999)
// 运行结果
这是lambda表达式,999
- Lambda表达式(函数形式)
// 例 1
fun main() {
add(1)
}
fun add(a: Int) = { b: Int, c: Int -> println(a + b + c) }
// 运行结果
// 无事发生
// 查看add反编译java后的结果
@NotNull
public static final Function2 add(final int a) {
return (Function2)(new Function2() {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1, Object var2) {
this.invoke(((Number)var1).intValue(), ((Number)var2).intValue());
return Unit.INSTANCE;
}
public final void invoke(int b, int c) {
int var3 = a + b + c;
boolean var4 = false;
System.out.println(var3);
}
});
}
// 从这个结果中看到它返回了一个Function2。
// 通过IDEA查看Function2的定义
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2): R
}
// 从它的定义可以看出它需要两个参数,而且需要这两个参数来调用函数,这里的两个参数表示
// 上面Lambda中的两个参数,即a和b。
// 因此如果想要打印结果,就需要通过invoke方法
fun main() {
add(1) // 这实际上只是创建了一个Function2对象
add(1).invoke(2,3) // 也可以使用add(1)(2,3)
}