Kotlin语言学习笔记(5)
委托模式(Delegation)
类的委托
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
这里 Derived 类使用 by 关键字将接口 Base 的实现委托给属性 b。
// 被委托的方法也可以被覆盖(重写)
interface Base {
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}
fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}
/*
abc10
*/
// 被委托的方法被覆盖(重写)时
// 所重写的方法不会被被委托方所调用,只能由委托方自己来调用
interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base) : Base by b {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
/*
BaseImpl: x = 10
Message of Derived
*/
属性的委托
class Example {
var p: String by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
val e = Example()
println(e.p)
// Example@33a17727, thank you for delegating ‘p’ to me!
e.p = "NEW"
// NEW has been assigned to ‘p’ in Example@33a17727.
这里属性 p 被委托给了 Delegate 类。
也就是读取属性 p 时 Delegate 类的 getValue 方法将被调用。
而在设置属性 p 时 Delegate 类的 setValue 方法将被调用。
标准的属性委托
Lazy
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
/*
computed!
Hello
Hello
*/
Observable
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
/*
<no name> -> first
first -> second
*/
委托给另一个属性
属性可以被委托给
- 顶层属性
- 所在类的其他属性,包括扩展属性
- 其他类(所在类的其他属性所属的类)的属性,包括扩展属性
var topLevelInt: Int = 0
class ClassWithDelegate(val anotherClassInt: Int)
class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
var delegatedToMember: Int by this::memberInt
var delegatedToTopLevel: Int by ::topLevelInt
val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt
// 使用例:被废弃的属性
class MyClass {
var newName: Int = 0
@Deprecated("Use 'newName' instead", ReplaceWith("newName"))
var oldName: Int by this::newName
}
fun main() {
val myClass = MyClass()
// Notification: 'oldName: Int' is deprecated.
// Use 'newName' instead
myClass.oldName = 42
println(myClass.newName) // 42
}
Map
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
局部属性委托
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
自定义的属性委托
可读属性的属性委托
- 属性委托由操作符函数 getValue 来实现
- thisRef 参数的类型必须是属性所属类或其超类
- property 参数的类型必须是 KProperty<*> 或其超类
- 函数返回值的类型必须是属性的类型或其超类
class Resource
class Owner {
val valResource: Resource by ResourceDelegate()
}
class ResourceDelegate {
operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
return Resource()
}
}
可读可写属性的属性委托
- 属性委托由操作符函数 setValue 来实现
- thisRef 参数的类型必须是属性所属类或其超类
- property 参数的类型必须是 KProperty<*> 或其超类
- value 参数的类型必须是属性的类型或其超类
class Resource
class Owner {
var varResource: Resource by ResourceDelegate()
}
class ResourceDelegate(private var resource: Resource = Resource()) {
operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
return resource
}
operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {
if (value is Resource) {
resource = value
}
}
}
解构声明(Destructuring Declarations)
解构声明:将某个对象分解成多个变量的声明。
// 解构声明
val (name, age) = person
println(name)
println(age)
// 解构声明的语义
val name = person.component1()
val age = person.component2()
// 在for循环中使用解构声明
for ((a, b) in collection) { ... }
// 返回多个值的函数
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// computations
return Result(result, status)
}
// Now, to use this function:
val (result, status) = function(...)
// 遍历map时使用解构声明
for ((key, value) in map) {
// do something with the key and the value
}
// 遍历map时能够使用解构声明的原因
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
// 在解构声明中使用下划线忽略某个变量
val (_, status) = getResult()
// 在lambda表达式中使用解构声明
map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }
// 参数语法
{ a -> ... } // one parameter
{ a, b -> ... } // two parameters
{ (a, b) -> ... } // a destructured pair
{ (a, b), c -> ... } // a destructured pair and another parameter
// 使用下划线
map.mapValues { (_, value) -> "$value!" }
// 指定参数的类型
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }
类型检查和类型转换
// 确认变量的类型使用 is 和 !is 运算符
if (obj is String) {
print(obj.length)
}
if (obj !is String) { // same as !(obj is String)
print("Not a String")
}
else {
print(obj.length)
}
// 智能类型转换
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
if (x !is String) return
print(x.length) // x is automatically cast to String
// x is automatically cast to string on the right-hand side of `||`
if (x !is String || x.length == 0) return
// x is automatically cast to string on the right-hand side of `&&`
if (x is String && x.length > 0) {
print(x.length) // x is automatically cast to String
}
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
// 安全及不安全的类型转换
val x: String = y as String
val x: String? = y as String?
val x: String? = y as? String
This 表达式
- 在类的内部,this指向当前对象
- 在扩展函数和带接收者的函数字面量中,this指向接收者对象。
- this缺省指向最内层对象,this可以带限定符。
class A { // implicit label @A
inner class B { // implicit label @B
fun Int.foo() { // implicit label @foo
val a = this@A // A's this
val b = this@B // B's this
val c = this // foo()'s receiver, an Int
val c1 = this@foo // foo()'s receiver, an Int
val funLit = lambda@ fun String.() {
val d = this // funLit's receiver
}
val funLit2 = { s: String ->
// foo()'s receiver, since enclosing lambda expression
// doesn't have any receiver
val d1 = this
}
}
}
}
// 隐式 this
fun printLine() { println("Top-level function") }
class A {
fun printLine() { println("Member function") }
fun invokePrintLine(omitThis: Boolean = false) {
if (omitThis) printLine()
else this.printLine()
}
}
A().invokePrintLine() // Member function
A().invokePrintLine(omitThis = true) // Top-level function