Kotlin核心编程知识点-01-基础语法

发布于:2024-05-23 ⋅ 阅读:(162) ⋅ 点赞:(0)

0.前言

简单的知识点记录而已,参考书籍《Kotlin核心编程》

1.不一样的类型声明

声明变量,类型在变量的后面,如下:

val a: String = "Im a Kotlin"
// 等价写法,省略类型声明,也就是下面1.1中的类型推导
val a = "Im a Kotlin"

1.1.增强的类型推导

编译器可以在不显示声明类型的情况在,自动推导出需要的类型,如下:

val svalue = "Im a Kotlin"  // java.lang.String
val ivalue = 123   // int
val lvalue = 123L  // long
val fvalue = 123F  // float
val dvalue = 123.12  // double

上述可以在REPL中打印这些变量的类型,如 println(svalue.javaClass.name) 。

类型推导提高Kotlin这种静态类型语言的开发效率。

1.2.声明函数返回值类型

虽然Kotlin支持类型推导,但不代表可以不声明函数的返回值类型。

先看看如何用关键字 fun 定义一个函数, 如下:

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

与声明变量一样,类型信息放在函数的后面,如果我们把返回的类型声明去掉就会报错,如下:

// 编译报错:Type mismatch: inferred type is Int but Unit was expected
fun sum(x: Int, y: Int) {
    return x + y
}

因为没有声明返回值的类型,函数默认为函数返回 Unit(相当于Java的 void ) 类型,但是方法体中实际 return 了 Int 类型,所以编译报错了。这种情况必须声明返回值类型

上面的函数还可以进一步增强写法,可以把函数体的 {} 去掉,用等号 = 定义函数,如下:

fun sum(x: Int, y: Int): Int = x + y
// 等价于,去掉了返回值类型
fun sum(x: Int, y: Int) = x + y

这种用单行表达式和等号的语法定义的函数,叫作表达式函数。普通的函数声明叫作代码块函数

在使用表达式函数定义的情况下,可以不声明函数的返回值类型。 但是如果递归,还是要声明返回值类型,如下:

// 没有返回值类型,会报错:Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly
fun foo(n: Int) = if (n == 0) 1 else n * foo(n - 1)
// 正确写法,加上返回值类型的声明
fun foo(n: Int): Int = if (n == 0) 1 else n * foo(n - 1)

编译器不能针对递归函数的情况推导类型。

1.3.是否需要显示声明类型?

  • 如果是一个函数的参数:必须声明(参数类型)。
  • 一个非表达式函数:那就是代码块函数,除非函数没有返回(Unit),否则必须声明(返回值类型的)。
  • 递归函数:必须声明(返回值类型)。
  • 其他情况:建议声明,增强代码的可读性。

2.val和var的使用规则

Kotlin声明变量使用 varval 的概念。

  • var相当于Java中的变量,可变的。
  • val相当于Java中的 final 修饰的变量,不可变的(引用不可变)。

2.1.val的含义:引用不可变

val声明的变量的引用不可变,但是引用对象可以变,如下:

// val定义一个数组
val x = intArrayOf(1,2,3)
// 修改数组的引用,会报错,因为x是val修饰,引用不可变,不能指向另一个数组
x = intArrayOf(2,3,4)  
// 修改引用对象的某个值,可以,结果是[6,2,3]
x[0] = 6  

因此 val 声明的变量是只读变量,它的引用不可变,但是引用的对象(的可变成员)可以变。如下:

// 这里Book类的参数使用var声明
class Book(var name: String){
    fun printName(): Unit {
        println("这本书的名字是:$name")
    }  	 
}

// 创建对象,打印name
val book: Book = Book("Kotlin核心编程")
book.printName()
// 修改Book的name的值,不报错,可以正常打印
book.name = "Java核心编程"
book.printName()

执行结果:

这本书的名字是:Kotlin核心编程
这本书的名字是:Java核心编程

如果把Book的参数 name 的参数类型改为 val,上述就会报错了。

注意,上述示例中类的使用后续会说明,这里只是说明 var 和 val 的区别。

开发中,建议优先使用 val、尽可能采用 val 、不可变对象以及纯函数(没有副作用的函数)来设计程序。

3.高阶函数和Lambda

函数式语言典型特征就是函数是头等公民,不仅可以像类一样在顶层直接定义一个函数,也可以在一个函数内部定义一个局部函数。

此外也可以直接将函数像普通变量一样传递给另一个函数,或者在其他函数内被返回。

3.1.抽象和高阶函数

抽象不多做解释,和Java的抽象一样理解。

高阶函数,可以理解为“把其他函数作为参数或者返回值的函数”,是一种高级的抽象机制,增强语言表达能力。

3.2.函数作为参数的需求

需求:有一堆人员Person的集合数据,有属性name、age和address,需要根据不同条件从集合中筛选人员,就可以把这里的“不同条件筛选”的行为抽象成一个参数,这个参数是一个类对象,也就是多个不同的筛选条件需求创建多个不同的类,这些类各自实现了一个筛选行为。

先定义一个data class声明Person数据类(后面会说明,其实就是相当于Java的POJO对象),如下:

// data class 声明一个Person数据类
data class Person(
    val name: String,
    val age: Int,
    val address: String
)

然后定义一个类,里面有一个方法,筛选符合条件的Person的方法,例如我们想要年龄age≥40岁的人员,如下:

class FilterPersonByAge {
	fun ageGe40Filter(person: Person): Boolean {
		return person.age >= 40
	}
}

现在,如何把上面类 FilterPersonByAge 的方法 ageGe40Filter 变成另一个函数的参数呢?也就是将 ageGe40Filter 变成一个函数类型的参数。

3.3.函数的类型

Kotlin中,函数类型的格式如下:

(Int) -> Unit

如上,Kotlin中的函数类型的声明遵循以下几点:

  • 通过 -> 符号来组织函数类型的参数类型和返回值类型,左边是参数类型,右边是返回值类型。
  • 必须用一个括号来包裹函数类型的参数类型。如果是一个没有参数的函数类型,参数类型部分用 () 表示,即 () -> Unit
  • 返回值类型即使是 Unit,也必须显示声明
  • 如果是多个参数的情况,使用逗号分割参数类型部分,即 (Int, String) -> Unit
  • Kotlin还支持为函数类型的参数类型部分指定名字,即 (errCode: Int, errMsg: String) -> Unit
  • 高阶函数支持返回另一个函数,即 (Int) -> ((Int) -> Unit),表示传入类型为Int的参数,返回另一个类型为 (Int) -> Unit 的函数,可以简化写法,即 (Int) -> Int -> Unit

所以,现在回到刚才Person筛选的问题,我们还缺少一个通过对Person数据进行筛选的过程方法,如下:

// 接收一个函数类型的参数test,函数的参数是Person类型,返回Boolean类型
fun filterPerson(persons: List<Person>, test: (Person) -> Boolean): List<Person> {
	
	val pList = mutableListOf<Person>()
	
	for (p in persons) {
		// 使用函数类型的参数进行筛选
		if (test(p)) {
			pList.add(p)
		}
	}
	
	return pList 
	
}

最后,如何将 FilterPersonByAge 类的方法 ageGe40Filter 作为一个参数传递给方法 filterPerson 呢?继续往下看。

3.4.方法和成员引用

Kotlin中,存在语法通过两个冒号来实现对某个类的方法进行引用,所以刚才的问题,我们需要将 FilterPersonByAge 类的方法 ageGe40Filter 作为一个参数传递给方法 filterPerson,就可以这么写,如下:

// 先创建类的对象实例
val filterPersonByAge= FilterPersonByAge()
// 引用方法
filterPersonByAge::ageGe40Filter

到这里,我们涉及到Person的筛选整个过程都完成了,上下文中的完整代码如下:

// 定义一个数据类Person
data class Person (
	val name: String,
    val age: Int,
    val address: String
)

// 创建一个筛选条件的类,实现一个筛选行为
// 不同的筛选条件,定义多个这样的类,但实现的方法都必须是 (Person) -> Boolean 的函数类型
class FilterPersonByAge {
    fun ageGe40Filter(person: Person): Boolean {
		return person.age >= 40
	}
}

// 筛选过程,根据不同的筛选条件test进行筛选
// 接受一个函数类型test的参数
fun filterPerson(persons: List<Person>, test: (Person) -> Boolean): List<Person> {	
	val pList = mutableListOf<Person>()
	for (p in persons) {
		// 使用函数类型的参数进行筛选
		if (test(p)) {
			pList.add(p)
		}
	}
	return pList 
}

fun main(){
    
    val p1 = Person("张三", 30, "北京")
	val p2 = Person("李四", 40, "上海")
	val p3 = Person("王五", 50, "深圳")
	val p4 = Person("赵六", 60, "广州")

	val allPersonList: List<Person> = listOf(p1, p2, p3, p4)
    
    // 方法引用
    val filterPersonByAge = FilterPersonByAge()
    val filterPersonList: List<Person> = filterPerson(allPersonList, filterPersonByAge::ageGe40Filter)
    
    for (p in filterPersonList) {
        println("筛选人员:${p}")
    }
    
}

执行代码,结果如下:

筛选人员:Person(name=李四, age=40, address=上海)
筛选人员:Person(name=王五, age=50, address=深圳)
筛选人员:Person(name=赵六, age=60, address=广州)

3.5.匿名函数

回顾上述Person筛选的过程,其中类 FilterPersonByAge 的定义不是很好的方案,因为每增加一个筛选条件就要定义一个类似的类,比较麻烦,所以可以使用匿名函数改进优化。

Kotlin支持在缺省函数名的情况在,直接定义一个函数,所以上述代码可以这样改造,取消类 FilterPersonByAge 以及方法 ageGe40Filter 定义,直接执行 filterPerson 方法的时候传递一个匿名函数,如下:

// 直接展示关键代码处改造
...
// 取消定义FilterPersonByAge以及方法引用, 直接传递匿名函数
val filterPersonList: List<Person> = filterPerson(allPersonList, fun(person: Person): Boolean {
    return person.age>=40
})
...

是不是更简洁了,其实还有更简单的方法进行优化,这就是Lambda表达式。

3.6.Lambda表达式

Lambda是更简单的概念,可以理解为简化表达后的匿名函数,实质上就是一种语法糖。

上面的 3.5.匿名函数 中,我们使用匿名函数进行了改进,这里分析一下这个匿名函数:

  • fun(person: Person)显得比较啰嗦,因为编译器会推导类型,所以只需要一个变量,如 person 就行了。
  • 匿名函数体中的关键字 return 也可以省略,这里返回的是一个有值的表达式。
  • 模仿函数类型的语法,可以用 -> 把参数和返回值连在一起。

如上,使用Lambda继续改进后就变成如下:

val filterPersonList: List<Person> = filterPerson(allPersonList, {
    person -> person.age>=40
})

这就是 Lambda 表达式,和匿名函数一样,是一种函数字面量,接着说明 Lambda 的具体语法。

先用 Lambda 表达式定义一个加法的操作:

// sum是定义的表达式,表达式的参数是两个Int类型,返回值是一个Int类型
val sum: (Int, Int) -> Int = {x: Int, y:Int -> x + y}

因为类型推导,这里可以简化如下:

// 声明了 Lambda 的参数类型,可以不声明 sum的函数类型
val sum = {x: Int, y:Int -> x + y}
// 等价于
// 声明了 sum的函数类型,可以不声明 Lambda 的参数部分类型
val sum: (Int, Int) -> Int = {x, y -> x + y}

如上,总结 Lambda 表达式的语法:

  • Lambda 表达式必须通过 {} 来包裹起来。
  • 如果 Lambda 声明了参数部分的类型,且返回值类型支持类型推导,那么 Lambda 变量就可以省略函数类型声明。
  • 如果 Lambda 声明了函数类型,那么 Lambda 的参数部分的类型可以省略。
  • 如果 Lambda 表达式的返回不是 Unit,那么默认最后一行表达式的值类型就是返回值类型。如:
val sum: (Int, Int) -> Int = {x: Int, y:Int -> 
    val s = x + y
    // 返回值是s
    s
}

3.7.函数、Lambda

我们很容易对Kotlin的 fun 声明函数、Lambda 表达式的语法产生混淆,因为它们都可以存在花括号 {},现在我们来做个区分:

  • fun 在没有等号、只有花括号的情况在,就是我们最常见的代码块函数体,如果返回类型不是 Unit,必须带着 return。如下:
fun foo(x: Int) {
   println(x)
} 
fun foo(x: Int, y: Int): Int{
    return x + y
}
  • fun 带有等号,是单表达式函数体,该情况下可以省略 return。如下:
fun foo(x: Int, y: Int) = x + y
  • 不管是 val/var 还是 fun,如果同时有等号、花括号的语法,那构建的就是一个 Lambda 表达式,Lambda 的参数在花括号内部声明。所以,如果左侧是 fun,那么就是 Lambda 式函数体,也必须通过 () 或者 invoke 来调用 Lambda,如:
// fun、等号、花括号,定义 Lambda 表达式
fun foo(x: Int, y: Int) = {x + y}
// val、等号、花括号,定义 Lambda 表达式
val foo1 = {x: Int, y: Int -> x + y}

// 调用Lambda表达式 foo
println(foo(1,2)())
println(foo(1,2).invoke())

// 调用Lambda表达式 foo1
println(foo1(2,2))
println(foo1.invoke(2,2))

4.面向表达式编程

4.1.枚举类和when表达式

这里介绍定义枚举结构以及一个非常强大的表达式,也就是when表达式。

下面我们先定义枚举,然后使用枚举进行when的使用来说明用法。

4.1.1.枚举是类

在 Kotlin 中,枚举是通过一个枚举类enum来实现的,如下:

enum class Day{
    MON,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
}

和Java类似,不同的是枚举类的定义多了一个 class 关键字,表示这是一个枚举类。

但是 Kotlin 的枚举类不简单,由于是一个类,自然也拥有构造函数,以及定义额外的属性和方法,如下:

enum class Day(val day: Int){
    MON(1),
    TUE(2),
    WED(3),
    THU(4),
    FRI(5),
    SAT(6),
    // 注意这里结尾有一个分号,为了和下面的方法或者属性定义区分开
    SUN(7);

    fun getDayNumber(): Int {
        return day
    }
}

需要注意,枚举类中如果存在额外的方法或者属性定义,必须在枚举项的最后一个结尾处追加分号,这是必须的。

4.1.2.用when代替if-else

上看了解了如何定义一个枚举类,现在我们使用枚举模拟业务,例如,给一周的几天计划了不同的活动,安排如下:

  • 周六周日打蓝球
  • 周五约会
  • 平时里如果晴天就学习,否则就睡觉

设计代码如下,利用一个函数并结合刚才的枚举进行表示:

fun schedule(day: Day, sunny: Boolean){
    if (day == Day.SAT && day == Day.SUN) {
        // 打篮球
    } else if (day == Day.FRI) {
        // 约会
    } else {
        if (sunny) {
            // 学习
        } else {
            // 睡觉
        }
    }
}

看起来很麻烦,存在了不少的if-else分支,更好的改进方案就是使用when表达式,如下:

fun schedule(day: Day, sunny: Boolean) = when(day) {
    Day.SAT,Day.SUN -> "打篮球"
    Day.FRI -> "约会"
    else -> when {
        sunny -> "学习"
        else -> "睡觉"
    }
}

是不是简单了很多。

4.1.3.when表达式具体语法

具体语法如下:

  1. 一个完成的 when 表达式类似 switch 语句,由 when 关键字开始,用花括号包含多个逻辑分支,每个分支由 -> 连接,不在需要 switch 的 break 关键字了,由上到下匹配,一直匹配完为止,否则执行 else 分支的逻辑,类似 switch 的 default。
  2. 每个逻辑分支具有返回值,最终整个 when 表达式的返回类型就是所有分支相同的返回类型,或公共的父类型。
  3. when 关键字的参数可以省略,如上面的例子中,else 分支中的 when 表达式就没有参数,只不过该情况下,分支 -> 的左侧部分需要返回布尔值(when没有参数的时候),否则编译报错。
  4. 表达式可以组合,上面的例子中,when 表达式中的 else 分支中还有一个 when,也就是嵌套了一层,可以如下修改:
// when的参数省略,里面的每一行表达式按照3中的要求,左侧是布尔值
fun schedule2(day: Day, sunny: Boolean): String = when {
    day == Day.SAT || day == Day.SUN -> "打篮球"
    day == Day.FRI -> "约会"
    sunny -> "学习"
    else -> "睡觉"
}

when是不是很优雅,其实when的实际使用中威力不仅如此,这里不多说明,后续会说明。

4.2.for循环和范围表达式

这里说明 for 循环的语法和引用。

4.2.1.for循环

在Java中,一个 for 循环的基本写法如下:

for (int i=1; i<=10; i++) {
	//
}

Kotlin中,for 循环的表达式更简洁,如下:

for (i in 1..10) {
    println(i)
}
// 等价于
for (i: Int in 1..10) {
    println(i)
}

此外,for 循环中我们还可以通过调用一个 withIndex 方法,提供一个键值元组:

val a = intArrayOf(1,2,3)
 
 for ((index, value) in a.withIndex()) {
     println("下标:$index, 数值:$value")
 }

4.2.2.范围表达式

上述的 for 循环中的 1…10 这种语法,就是范围表达式(range),Range 表达式是通过 rangeTo 函数实现的,通过 “…” 操作符和某种类型的对象组成,除了整型的基本类型外,该类型需要实现 java.lang.Comparable 接口

另外,当对整数进行 for 循环时,Kotlin 还提供了一个 step 函数来定义迭代的步长,如下:

// 打印结果是 1,3,5,7,9
for (i in 1..10 step 2) {
    println(i)
}

如果是倒序呢?可以使用 downTo 方法实现:

// 打印结果是 10,8,6,4,2
for (i in 10 downTo 1 step 2 ) {
    println(i)
}

另外还有一个 until 函数实现一个半开区间,如下:

// 打印结果是 1,2,3,4,5,6,7,8,9 并不包含10
for (i in 1 until 10 ) {
    println(i)
}

4.2.3.用in检查成员关系

in 关键字,在 Kotlin 中还可以用来检查一个元素是否是另一个区间或集合中的成员,举例如下:

// 结果是 true
"a" in listOf<String>("b","c","d","a")

如果在 in 前面加上感叹号,那就是相反的判断结果:

// 结果是 false
"a" !in listOf<String>("b","c","d","a")

in 还可以结合范围表达式来表示更多的含义:

4.2.4.函数可变参数

Kotlin 通过关键字 vararg 来定义函数中的可变参数,类似 Java 中的 “…” 的效果。

需要注意,Java 中的可变参数必须位于方法的最后一个参数,Kotlin 可没有这个限制(不过调用的时候有点不同)。

同样的,Kotlin 的可变参数在函数体中也是以数组的方式来使用可变参数的,如下:

// 可变参数names位于函数第一个参数
fun printlnNames(vararg names: String, msg: String) {
    println(msg)
    for (name in names) {
        println(name)
    }
}
// 调用的时候,第二个参数通过指定参数名区分开可变参数
printlnNames("张三", "李四", "王五", msg = "下面有请运动员入场:")

如果可变参数位于函数最后一个,那就可以不指定参数名了,如下:

fun printlnNames( msg: String, vararg names: String) {
    println(msg)
    for (name in names) {
        println(name)
    }
}
printlnNames("下面有请运动员入场:","张三", "李四", "王五")

此外,还可以使用星号(*)来传入函数外部的变量作为可变参数的变量,如下:

fun printlnNames( msg: String, vararg names: String) {
    println(msg)
    for (name in names) {
        println(name)
    }
}

val namearr = arrayOf("张三", "李四", "王五")

printlnNames("下面有请运动员入场:", *namearr)

4.3.中缀表达式

上面我们已经见识到了不少 Kotlin 中的奇特用法,例如 in、step、downTo、until,它们可以不通过点号,而是通过中缀表达式来调用,从而更简洁直观,这些是如何实现的呢?

先看 Kotlin 标准库中另一个类似的方法 to 的设计,这是一个通过泛型实现的方法,可以返回一个 Pair,如下:

public infix fun <A, B> A.to(that: B): Pair<A, B>

在 Kotlin 中,to 这种形式定义的函数成为 中缀函数,一个中缀函数的表达形式非常简单,可以理解成这样:

A 中缀方法 B

可以发现,如果我们要定义一个中缀函数,需要满足如下条件:

  • 该中缀函数必须是某个类型的扩展函数或者成员方法。
  • 该中缀函数只能有一个参数。
  • 虽然 Kotlin 的函数参数支持默认值,但是中缀函数不能有默认值,否则以上形式的 B 会缺失,从而对中缀表达式的语义造成破坏。
  • 同样,该参数也不能是可变参数,因为需要保持参数始终为1个。

由于 to 会返回 Pair 这种键值对的结构数据,因此经常把它和 Map 结合在一起使用,如下:

mapOf(1 to "one", 2 to "two", 3 to "three")

现在再自定义一个中缀函数,如下:

class Person {
	// 使用 infix 修饰
   infix fun called(name: String){
      println("My name is $name")
   }
} 

因为方法 called 使用了 infix 修饰,所以这样调用:

val person = Person()
// 结果打印:My name is Kotlin
person called "Kotlin"

同样的,上面也可以使用普通的语法调用这个中缀函数,如下:

// 结果打印:My name is Java
person.called("Java")

上述的完整代码如下:

class Person {
	// infix修饰,中缀函数的定义
   infix fun called(name: String){
      println("My name is $name")
   }
}

val person = Person()

// 中缀函数调用
person called "Kotlin"
// 普通语法调用
person.called("Java")

5.字符串的定义和操作

现在开始说明 Kotlin 中的字符串基础语法。

和 Java 一样,也是通过双引号定义字符串,是不可变的对象。

val str = "hello world"

熟悉的操作如下:

// 11
println(str.length)
// hello
println(str.substring(0,5))
// hello world, !!!
println(str + ", !!!")
// hello Kotlin
println(str.replace("world", "Kotlin"))

String 是一个字符序列,所以可以进行遍历:

// 打印结果:HELLO WORLD
for (c in str.uppercase()) {
   print(c)
}

还可以访问字符序列的成员

// h
println(str[0])
// h
println(str.first())
// d
println(str.last())
// d
println(str[str.length - 1])

此外,Kotlin 的字符串还有很多丰富的 API,如下:

// true
println("".isEmpty())
// false
println(" ".isEmpty())
// true
println(" ".isBlank())
// ed
str.filter { c -> c in 'a'..'e' }.forEach { c -> print(c) }

更多的字符串的语法,请查阅 Kotlin API 文档

5.1.定义原生字符串

Kotlin 中,支持原生字符串,如下:

val str = """
   hello, my name is kotlin,
   \n today verry happy, because i am a kotlin programmer.
   \n hahaha ...
   bye ~~~
"""

println(str)

打印结果如下:

      hello, my name is kotlin,
      \n today verry happy, because i am a kotlin programmer.
      \n hahaha ...
      bye ~~~

简而言之,用这种三个双引号定义的字符串,最终的打印格式和代码中呈现的格式一致,不会解释转化为转义字符,例如上面的 \n。

原生字符串如果来描述 HTML,会非常方便。

5.2.字符串模板

先看一个字符串常见的拼接:

fun printlnInfo(name: String, age: Int){
   println("my name is " + name + ", age is " + age)
}

一个简单的拼接,用了2个加号,如果多变量就更繁琐了,而 Kotlin 引入了字符串模板改进了这一点,支持将变量植入字符串,高进上述代码,如下:

fun printlnInfo(name: String, age: Int) {
    println("my name is ${name}, age is ${age}")
}

通过${name}这种格式将变量传入字符串,最终提高了代码的紧凑性和可读性。

除了上面将变量传入字符串,也可以将表达式传入,并且支持在表达式中使用双引号,如下:

val name = "Kotlin"
val hobby = "2"

val message = "my name is ${name}, my hobby is ${ if(hobby == "1") "篮球" else "足球" }"

println(message)

5.3.字符串判等

Kotlin 中的判等性主要有两种类型:

  • 结构相等:通过操作符 == 来判断两个对象的内容是否想等。
  • 引用相等:通过操作符 === 来判断两个对象的引用是否一样,与之相反的判断操作符是 !==。如果比较的实在运行时的原始类型,比如 Int,那么 === 判断的效果也等价于 ==。

具体例子检测字符串两种类型的判等性:

var a = "Java"
var b = "Java"
var c = "Kotlin"
var d = "Kot"
var e = "lin"
var f = d + e

// true
println(a == b)
// true
println(a === b)
// true
println(c == f)
// false
println(c === f)

6.总结

6.1.类型推导

Kotlin 拥有比 Java 更强大的类型推导功能,避免了静态语言在编码时需要书写大量类型的弊端。

但这不是万能的,在使用代码块函数体时,必须显示声明返回值类型。

此外一些复杂的情况,例如递归,返回值类型也不能省略。

6.2.变量声明

Kotlin 中使用 var 和 val 声明变量以及一些类的成员属性,代表它们的引用可变性。

开发中优先推荐使用 val。

6.3.函数声明

Kotlin 中,普通的函数分为代码块体和表达式体,前者类似 Java 中定义函数的习惯,后者因为是一个表达式,可以说省略 return 关键字。

6.4.高阶函数

Kotlin 中函数是头等公民,所以程序中可以到处声明函数,也可以作为值传递以及作为另一个函数的返回值。

函数作为参数的时候,需要使用函数引用表达式进行传值。

柯里化是函数作为返回值的一种应用,但是很少使用。

6.5.Lambda表达式

可以当做另一种匿名函数。

6.6.表达式和流程控制

表达式更加安全,更利于组合,且更强的表达能力。

流程控制可以利用 if、when、try、range、中缀等表达式,写出更强大的代码。

for 循环更简洁。

6.7.字符串操作

字符串是不可变对象,有丰富的API。

支持原生字符串、字符串模板等功能。


网站公告

今日签到

点亮在社区的每一天
去签到