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

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。

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

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值