麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > 綜合 > 正文

Kotlin代理屬性--官方文檔翻譯

2024-07-21 23:03:36
字體:
來源:轉載
供稿:網友

代理屬性 Delegated Properties

一些特定的常見類型的屬性, 盡管我們可以在每次需要的時候實現他們, 但是如果我們一次把他們全部實現并放在一個庫中, 這會非常方便, 包括:

延遲屬性: 只在第一次訪問的時候計算值

廣播屬性: 當屬性的值改變時通知觀察者

將數據存儲在鍵值對中, 而不是獨立的域中.

Kotlin提供的代理屬性, 包含了這些(以及其他)例子:

class Example{

var p: String by Delegate()

}

語法是:val/var : by . 在by關鍵字后面的語句是delegate, 因為屬性的get()和set()將被代理給它的getValue()和setValue()方法.

屬性代理不需要實現任何接口, 但他們需要提供一個getValue()方法(對于var---還需要提供setValue()).

例如:

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.'")

}

}

當我們從被代理給Delegate實例的p時,Delegate的getValue()方法被調用,

第一個參數是讀取p所在的對象, 第二個參數保存p自身的描述(例如: 你可以獲取它的名字). 例如:

val e = Example()

println(e.p)

打印結果:

Example@33a17727, thank you for delegating ‘p’ to me!

類似的, 當我們給p賦值時,setValue()方法被調用. 前兩個參數是相同的, 第三個參數保存被賦的新值:

e.p = "NEW"

打印結果:

NEW has been assigned to ‘p’ in Example@33a17727.

關于代理對象的需求的說明可以在[這里]找到(delegated-properties.html#property-delegate-requirements).

需要注意的是從Kotlin 1.1之前你可以在方法或代碼塊中聲明代理屬性了, 代理屬性不必聲明為類的成員,例子.

標準庫中的代理 Standard Delegates

Kotlin標準庫為一些常用的代理提供了工廠方法.

延遲屬性 Lazy

lazy()方法接收一個lamda作為參數并返回一個Lazy實例, 可以實現延遲加載:

第一次調用get()時執行傳入lazy()的lambda表達式并保存結果, 后續對get()的調用只返回保存的結果.

val lazyValue: String by lazy {

println("computed!")

"Hello"

}

fun main(args: Array) {

println(lazyValue)

println(lazyValue)

}

該例子輸出:

computed!

Hello

Hello

同步的

默認情況下, 延遲屬性的計算是(synchronized): 只有一個線程計算該值, 其他的線程都會看見相同的值. 如果此初始化的步驟不需要同步, 多個線程可以同事執行初始化, 在lazy()方法中傳入LazyThreadSafetyMode.PUBLICATION作為參數.

如果可以確保初始化過程只會在單個線程中執行, 可以用LazyThreadSafetyMode.NONE模式, 該模式不保證線程安全, 避免相關的開銷.

監控屬性 Observable

Delegates.observable()有兩個參數: 初始值和變化觀察器.

每次代理屬性被賦予值的時候都會調用觀察器(在賦值操作之后).觀察器有三個參數:屬性類型, 舊值和新值.

import kotlin.properties.Delegates

class User {

var name: String by Delegates.observable("") {

prop, old, new ->

println("$old -> $new")

}

}

fun main(args: Array) {

val user = User()

user.name = "first"

user.name = "second"

}

該例子輸出

-> first

first -> second

如果你想終端賦值的過程并拒絕賦值, 用vetoable()替代observable().

observable()的觀察器參數是在賦值之前被調用的.

使用Mapc存儲屬性 Storing Properties in a Map

在map中存儲屬性是一種常見使用方式.

這種情形在解析JSON或者其他"動態的"事情時經常出現.

在這種情況下, 你可以使用map的實例來代理一個代理屬性.

classUser(val map: Map) {

val name: String by map

val age: Int by map

}

在這個例子中, 構造器接收一個map:

val user = User(mapOf(

"name" to "John Doe",

"age" to 25

))

代理屬性從這個map接收值(通過String類型的key --- 作為屬性的名字)

println(user.name) // Prints "John Doe"

println(user.age) // Prints 25

當使用MutableMap而不是只讀的Map時, 對var也可以使用.

classMutableUser(val map: MutableMap) {

var name: String by map

var age: Int by map

}

本地代理屬性 Local Delegated Properties (since 1.1)

你可以聲明局部變量作為代理屬性.

例如, 可以讓局部變量成為lazy屬性.

fun example(computeFoo: () -> Foo) {

val memoizedFoo by lazy(computeFoo)

if (someCondition && memoizedFoo.isValid()) {

memoizedFoo.doSomething()

}

}

memoizedFoo變量只會在第一次訪問時計算.

如果someCondition失敗了, 變量的值則完全不會進行計算.

屬性代理的需求 Property Delegate Requirements

在此我們整理一下代理對象的需求.

只讀

對于一個屬性(例如:val), 代理必須提供一個接收下列參數的getValue函數:

thisRef--- 必須是_屬性擁有者_相同類型或者是其超類(對于擴展屬性 --- 則是其所擴展的屬性)

property--- 必須是KProperty<*>類型或其超類,

這個函數必須返回和屬性相同的類型, 或者其子類.

可變

對于的屬性(比如var), 代理必須額外提供具備下列參數的setValue函數:

thisRef--- 與getValue()相同,

property--- 與getValue()相同,

new value --- 必須是與屬性或其超類相同的類型

getValue()和/或setValue()函數可以用兩種方式提供: 代理類的成員函數或者擴展函數.

后者在原有對象沒有提供這些函數時非常方便.兩種方式的函數都要使用operator關鍵字修飾.

代理類可以實現下面的接口之一, 包含operator方法的ReadOnlyProperty和ReadWriteProperty接口. 這些接口在Kotlin標準庫中聲明.

interface ReadOnlyProperty {

operator fun getValue(thisRef: R, property: KProperty<*>): T

}

interface ReadWriteProperty {

operator fun getValue(thisRef: R, property: KProperty<*>): T

operator fun setValue(thisRef: R, property: KProperty<*>, value: T)

}

翻譯規則 Translation Rules

在代理屬性的背后, Kotlin編譯器生成一個輔助屬性并代理給它. 比如, 對于屬性prop, 會生成一個prop$delegate輔助屬性, 訪問器的代碼就是簡單的代理給這個附加的屬性:

class C {

var prop: Type by MyDelegate()

}

// this code is generated by the compiler instead:

class C {

private val prop$delegate = MyDelegate()

var prop: Type

get() = prop$delegate.getValue(this, this::prop)

set(value: Type) = prop$delegate.setValue(this, this::prop, value)

}

Kotlin編譯器提供了所有prop屬性必需的信息: 第一個參數this引用指向包含它的外部類C,this::prop是prop自身的反射類型信息, 是KProperty類型.

提供代理 Providing a delegate (since 1.1)

通過定義provideDelegate操作符可以擴展創建屬性實現所代理對象的邏輯.如果by右側使用的對象定義了provideDelegate作為成員函數或者擴展函數, 這個函數會在創建屬性代理時被調用.

One of the possible use cases ofprovideDelegateis to check property consistency when the property is created, not only in its getter or setter.

provideDelegate一個可能的用法是用來在創建屬性期間檢查屬性的一致性, 而不是在getter或setter中.

比如你想在綁定前檢查屬性的名字, 可以這樣寫:

class ResourceLoader(id: ResourceID) {

operator fun provideDelegate(

thisRef: MyUI,

prop: KProperty<*>

): ReadOnlyProperty {

checkProperty(thisRef, prop.name)

// 創建代理

}

private fun checkProperty(thisRef: MyUI, name: String) { ... }

}

fun bindResource(id: ResourceID): ResourceLoader { ... }

class MyUI {

val image bybindResource(ResourceID.image_id)

val text bybindResource(ResourceID.text_id)

}

provideDelegate和getValue的參數相同:

thisRef--- 必須與屬性的擁有者或其超類類型相同(對于擴展屬性 -- 指被擴展的類)

property--- 必須是KProperty<*>類型或其超類.

TheprovideDelegatemethod is called for each property during the creation of theMyUIinstance, and it performs the necessary validation right away.

provideDelegate方法在每個MyUI實例創建期間都被調用, 并立即進行必要的檢驗.

如果沒有這種在屬性和其代理之間攔截的手段, 要明確的傳入屬性命, 這很不方便.

// 沒有"provideDelegate"的情況下檢查屬性命

class MyUI {

val image by bindResource(ResourceID.image_id, "image")

val text by bindResource(ResourceID.text_id, "text")

}

fun MyUI.bindResource(

id: ResourceID,

propertyName: String

): ReadOnlyProperty {

checkProperty(this, propertyName)

// 創建委托

}

在生成的代碼中,provideDelegate被調用, 以此來初始化輔助prop$delegate屬性. 比較聲明是val prop: Type by MyDelegate()的屬性生成的代碼和上面不提供provide Delegate函數的代碼.

class C {

var prop: Type by MyDelegate()

}

// 在提供`provideDelegate`函數時, 這些代碼由編譯器生成

class C {

// 調用"provideDelegate"函數創建額外的"delegate"屬性

private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)

val prop: Type

get() = prop$delegate.getValue(this, this::prop)

}

注意provideDelegate函數只影響輔助屬性的創建, 并不影響getter和setter的生成.

本文為個人翻譯的Kotlin官方文檔, 原文連接:Delegated Properties


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 欧美一级鲁丝片免费看 | 我爱我色成人网 | 午夜亚洲视频 | 欧美日韩亚洲在线观看 | 看全色黄大色黄大片女图片 | bt 自拍 另类 综合 欧美 | 九九热免费观看 | 99riav国产在线观看 | 亚洲第一视频在线 | 欧美一级电影网 | 看免费黄色大片 | 国产精品久久久久久久久久10秀 | www.精品久久 | 久久网站免费 | 久久男人| 激情久久精品 | 中文字幕在线观看国产 | 久久久久久久久久美女 | 国产区二区 | 日韩字幕在线 | 精品国产一区三区 | 国产精品久久久久久久久粉嫩 | 毛片一级片 | freexxxhd喷水| 91久久久久久久一区二区 | 日本a级一区 | 欧美 亚洲 视频 | 天天色综合6 | 国产精品久久久久久久av三级 | 久久精品久久久久 | 久久久久久免费 | 亚洲一区二区免费 | 一级黄色在线观看 | 一本一本久久a久久精品综合小说 | 久久91久久久久麻豆精品 | 精品中文字幕在线播放 | 国产精品久久久久久婷婷天堂 | 成人午夜淫片a | 国产精品视频在线观看免费 | 国产精品免费麻豆入口 | 国产亚洲黑人性受xxxx精品 |