Kotlin 語(yǔ)法基礎(chǔ)大全再姑,從例子著手的 從0到1的學(xué)習(xí) -- 基礎(chǔ)介紹
Kotlin 語(yǔ)法基礎(chǔ)大全,從例子著手的 從0到1的學(xué)習(xí) -- 流程控制
Kotlin 語(yǔ)法基礎(chǔ)大全找御,從例子著手的 從0到1的學(xué)習(xí) -- 特殊的類
Kotlin 語(yǔ)法基礎(chǔ)大全元镀,從例子著手的 從0到1的學(xué)習(xí) -- 函數(shù)
Kotlin 語(yǔ)法基礎(chǔ)大全绍填,從例子著手的 從0到1的學(xué)習(xí) -- 集合
Kotlin 語(yǔ)法基礎(chǔ)大全,從例子著手的 從0到1的學(xué)習(xí) -- 作用域
Kotlin 語(yǔ)法基礎(chǔ)大全栖疑,從例子著手的 從0到1的學(xué)習(xí) -- 代理
Kotlin 語(yǔ)法基礎(chǔ)大全讨永,從例子著手的 從0到1的學(xué)習(xí) -- 產(chǎn)品級(jí)特性
翻譯來(lái)源
Delegation Pattern 委托模式
kotlin 天然支持 委托代理模式,不再需要編寫(xiě)一些模板文件遇革。
interface SoundBehavior { // 1
fun makeSound()
}
class ScreamBehavior(val n:String): SoundBehavior { // 2
override fun makeSound() = println("${n.toUpperCase()} !!!")
}
class RockAndRollBehavior(val n:String): SoundBehavior { // 2
override fun makeSound() = println("I'm The King of Rock 'N' Roll: $n")
}
// Tom Araya is the "singer" of Slayer
class TomAraya(n:String): SoundBehavior by ScreamBehavior(n) // 3
// You should know ;)
class ElvisPresley(n:String): SoundBehavior by RockAndRollBehavior(n) // 3
fun main() {
val tomAraya = TomAraya("Thrash Metal")
tomAraya.makeSound() // 4
val elvisPresley = ElvisPresley("Dancin' to the Jailhouse Rock.")
elvisPresley.makeSound()
}
/*
THRASH METAL !!!
I'm The King of Rock 'N' Roll: Dancin' to the Jailhouse Rock.
*/
- 1 定義一個(gè)接口
- 2 定義兩個(gè)實(shí)現(xiàn)類卿闹,
ScreamBehavior
和RockAndRollBehavior
。他們都實(shí)現(xiàn)了SoundBehavior
的接口萝快。 - 3
TomAraya
和ElvisPresley
也是先了SoundBehavior
的接口锻霎,但是他們沒(méi)有提供實(shí)現(xiàn),而是將實(shí)現(xiàn)委托給了ScreamBehavior
和RockAndRollBehavior
揪漩。通過(guò)一個(gè)by
關(guān)鍵字旋恼,這個(gè)委托就產(chǎn)生了,你看沒(méi)有一絲一毫的多余代碼奄容。 - 4 當(dāng)調(diào)用了 tomAraya 的
makeSound()
或者嗲用 elvisPresley 的makeSound()
的時(shí)候冰更,他們分別調(diào)用了他們的委托類。
Delegated Properties 代理屬性
kotlin 提供了一種代理屬性的機(jī)制,這個(gè)機(jī)制允許你將一個(gè)屬性的get set 方法委托給某一個(gè)實(shí)例昂勒,這個(gè)實(shí)例必須有getValue
方法蜀细,如果待委托的屬性還是一個(gè)可變屬性那么 setValue
也是必須的。
import kotlin.reflect.KProperty
class Example {
var p: String by Delegate() // 1
override fun toString() = "Example Class"
}
class Delegate() {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String { // 2
return "$thisRef, thank you for delegating '${prop.name}' to me!"
}
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) { // 2
println("$value has been assigned to ${prop.name} in $thisRef")
}
}
fun main() {
val e = Example()
println(e.p)
e.p = "NEW"
}
/*
Example Class, thank you for delegating 'p' to me!
NEW has been assigned to p in Example Class
*/
- 1 委托屬性
p
類型是String
被委托給了一個(gè)classDelegate
的實(shí)例叁怪,這個(gè)實(shí)例用by
關(guān)鍵字定義在 p之后审葬。 - 2 委托類里面的委托方法,這個(gè)方法的簽名必須和這里一摸一樣奕谭。方法里面你可以由自己決定需要幾步操作涣觉。如果是不可變屬性那么只有g(shù)etValue 是必須的。
標(biāo)準(zhǔn)庫(kù)里的delegate
kotlin的標(biāo)準(zhǔn)庫(kù)里面提供了一大堆有用的delegate血柳,比如 lazy
observable
等等官册。比如lazy
的使用方法。
class LazySample {
init {
println("created!") // 1
}
val lazyStr: String by lazy {
println("computed!") // 2
"my lazy"
}
}
fun main() {
val sample = LazySample() // 1
println("lazyStr = ${sample.lazyStr}") // 2
println(" = ${sample.lazyStr}") // 3
}
/*
created!
computed!
lazyStr = my lazy
= my lazy
*/
- 1 lazy 的屬性不會(huì)在類實(shí)例創(chuàng)建的時(shí)候初始化
- 2 第一次調(diào)用
lazyStr
的get()
的時(shí)候难捌,才會(huì)調(diào)用lazy類的實(shí)例的提供的表達(dá)式膝宁,返回一個(gè)"my lazy"。這個(gè)mylazy將會(huì)被賦值給lazyStr - 3 再次調(diào)用get的時(shí)候?qū)?huì)直接返回之前儲(chǔ)存的值根吁。
如果你想要一個(gè)線程安全的 延遲初始化方案员淫,請(qǐng)使用 blockingLazy()
代替。他保證了 getValue 后者 setValue 會(huì)只在一個(gè)線程上運(yùn)行击敌,并且所有的線程都可以讀取到同樣的值介返。
保存屬性到 map
屬性委托,同樣可以用于保存內(nèi)容到map 。這是很方便地用于類似于解析json圣蝎,或者其他的什么東西之上的刃宵。
class User(val map: Map<String, Any?>) {
val name: String by map // 1
val age: Int by map // 1
}
fun main() {
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
println("name = ${user.name}, age = ${user.age}")
}
//name = John Doe, age = 25
- 1 在這里 map 內(nèi)部提供過(guò)來(lái) delegate 屬性類的作用,當(dāng)調(diào)用user的屬性的get的時(shí)候徘公,會(huì)去map中取出value牲证,key是user屬性的名字。
當(dāng)然你也可以用可變屬性 不需要一定要val 的屬性关面,只是你需要注意的是 如果你定義的是可變屬性坦袍,那么你傳入的map 也必須是可變map