0%

Kotlin上路

开始

对一个对象实例调用多个方法(使用 with)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}

val myTurtle = Turtle()
with(myTurtle) { // 画一个 100 像素的正方形
penDown()
for(i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}

配置对象的属性(使用 apply)

1
2
3
4
5
val myRectangle = Rectangle().apply {
length = 4
breadth = 5
color = 0xFAFAFA
}

类与对象

属性与字段

幕后字段

1
2
3
4
var counter = 0 // Note: the initializer assigns the backing field directly
set(value) {
if (value >= 0) field = value
}

value的值指定counter的值。

幕后属性

1
2
3
4
5
6
7
8
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap()
}
return _table ?: throw AssertionError("Set to null by another thread")
}

可见性修饰符

类、对象、接口、构造函数、方法、属性和它们的 setter 都可以有可见性修饰符(getter 与属性有相同的可见性)。

Kotlin 中有 private protected internal public 四个可见性修饰符,默认是public

internal 模块内可见。

注意:Kotlin 中,外部类不能访问到内部类的private成员。

对象声明

即一个关键字object 实现单例。

伴生对象

companion关键字声明伴生对象,即类内部的对象。

1
2
3
4
5
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}

委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Base {
fun print()
}

class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main() {
val b = BaseImpl(10)
Derived(b).print()
}

可以看到Derived类相比普通的声明多了by b这部分,这部分的意思就是说b的公有成员都委托给Derived

委托属性

标准委托

Kotlin 标准库中内置了几种委托。

延迟属性 Lazy

lazy()接受一个 lambda 并返回一个Lazy<T>的实例,返回的实例作为延迟属性的委托。第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只返回记录的结果。

可观察属性 Observable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import kotlin.properties.Delegates

class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println(prop)
println("$old -> $new")
}
}

fun main() {
val user = User()
user.name = "first"
user.name = "second"
}

Delegates.observable()接受两个参数初始值inintalValue和值改变时的回调方法onChangeonChange接受三个参数:被赋值的属性,旧值,新值。在回调方法被调用前,值已经改变过了。

image.png

如果需要拦截新值并否决,可以使用vetoable()代替observable(),在新值生效前会调用回调方法。

把属性储存在 map 中
1
2
3
4
5
6
7
8
9
10
11
12
13
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}

fun main() {
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
}

函数

函数可以有默认参数。当覆盖(重写)一个有默认参数的函数时,新函数不可以设置默认值。

当向函数传递参数时,可以指定参数的名称。

函数的可变参数(通常是最后一个)可以用 vararg 修饰符标记。当把一个数组a传给可变参数,可以用*a(伸展操作符 Spread )。

中缀表示函数:

1
2
3
4
5
6
7
infix fun Int.shl(x: Int): Int { …… }

// 用中缀表示法调用该函数
1 shl 2

// 等同于这样
1.shl(2)

高阶函数和 Lambda 表达式

高阶函数是将函数用作参数或返回值的函数。

Kotlin 中,如果一个函数的参数的最后一个参数为函数,则这个函数参数可以放在()外,写在{}里。更甚,如只有一个参数且为函数,则()也可省略。

Lambda 表达式或者匿名函数(以及局部函数对象表达式) 可以访问其 闭包 ,即在外部作用域中声明的变量。 在 lambda 表达式中可以修改闭包中捕获的变量:

1
2
3
4
5
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)

内联函数

inline修饰符会影响函数本身和传给它的 lambda 表达式,它们被内联到调用处,可以提高一些效率。

1
inline fun <T> lock(lock: Lock, body: () -> T): T { …… }
1
lock(l) { foo() }
1
2
3
4
5
6
7
l.lock()
try {
foo()
}
finally {
l.unlock()
}

扩展函数

1
2
3
4
5
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
1
2
val list = mutableListOf(1, 2, 3)
list.swap(0, 2)

作用域函数

函数 对象引用 返回值 是否是扩展函数
let it Lambda 表达式结果
run this Lambda 表达式结果
run - Lambda 表达式结果 不是:调用无需上下文对象
with this Lambda 表达式结果 不是:把上下文对象当做参数
apply this 上下文对象
also it 上下文对象

协程

参考

Reference - Kotlin 语言中文站

2020-3-17 23:50:39