Trong khi phát triển cho Android, đôi khi tôi gặp một cái gì đó giống như sau:
var someModel: someViewModel by notNullAndObservable { vm ->
...
}
Tôi không hiểu ý nghĩa của by
từ khóa là gì.
Câu trả lời:
Trong tài liệu tham khảo Kotlin, bạn sẽ tìm thấy hai cách sử dụng, cách sử dụng by
đầu tiên là Thuộc tính được ủy quyền là cách sử dụng bạn có ở trên:
Có một số loại thuộc tính phổ biến nhất định, mặc dù chúng ta có thể triển khai chúng theo cách thủ công bất cứ khi nào chúng ta cần, nhưng sẽ rất tốt nếu thực hiện một lần và mãi mãi, và đưa vào thư viện. Ví dụ bao gồm các thuộc tính lười biếng: giá trị chỉ được tính khi truy cập lần đầu, các thuộc tính có thể quan sát được: người nghe nhận được thông báo về các thay đổi đối với thuộc tính này, lưu trữ các thuộc tính trong một bản đồ, không phải trong từng trường riêng biệt.
Ở đây bạn ủy quyền getter / setter cho một lớp khác thực hiện công việc và có thể chứa mã chung. Như một ví dụ khác, một số bộ tiêm phụ thuộc cho Kotlin hỗ trợ mô hình này bằng cách ủy quyền bộ nhận để nhận một giá trị từ sổ đăng ký các phiên bản được quản lý bởi công cụ tiêm phụ thuộc.
Và ủy quyền Giao diện / Lớp là cách sử dụng khác:
Mẫu ủy quyền đã được chứng minh là một giải pháp thay thế tốt cho việc kế thừa triển khai và Kotlin hỗ trợ nó nguyên bản không yêu cầu mã soạn sẵn. Một lớp Derived có thể kế thừa từ một Cơ sở giao diện và ủy quyền tất cả các phương thức công khai của nó cho một đối tượng được chỉ định
Ở đây bạn có thể ủy quyền một giao diện cho một triển khai khác để lớp thực thi chỉ cần ghi đè những gì nó muốn thay đổi, trong khi phần còn lại của các phương thức ủy quyền lại cho một triển khai đầy đủ hơn.
Một ví dụ trực tiếp sẽ là các bộ sưu tập Klutter Readonly / Immutable , nơi chúng thực sự chỉ ủy quyền giao diện bộ sưu tập cụ thể cho một lớp khác và sau đó ghi đè bất kỳ thứ gì cần khác trong việc triển khai chỉ đọc. Tiết kiệm rất nhiều công việc mà không phải ủy quyền thủ công tất cả các phương pháp khác.
Cả hai điều này đều được bao phủ bởi tài liệu tham khảo ngôn ngữ Kotlin , hãy bắt đầu từ đó cho các chủ đề cơ bản của ngôn ngữ.
Nói một cách dễ hiểu, bạn có thể hiểu by
từ khóa như được cung cấp bởi .
Từ quan điểm của người tiêu dùng tài sản, val
là thứ có getter (lấy) và var
là thứ có getter và setter (lấy, đặt). Đối với mỗi thuộc var
tính có một nhà cung cấp mặc định các phương thức get và set mà chúng ta không cần chỉ định rõ ràng.
Tuy nhiên, khi sử dụng by
từ khóa, bạn đang nói rằng getter / getter & setter này được cung cấp ở nơi khác (tức là nó đã được ủy quyền). Nó được cung cấp bởi chức năng đi sau by
.
Vì vậy, thay vì sử dụng các phương thức get và set tích hợp sẵn này, bạn đang ủy quyền công việc đó cho một số hàm rõ ràng.
Một ví dụ rất phổ biến là by lazy
thuộc tính tải lười biếng. Ngoài ra, nếu bạn đang sử dụng thư viện tiêm phụ thuộc như Koin, bạn sẽ thấy nhiều thuộc tính được định nghĩa như sau:
var myRepository: MyRepository by inject() //inject is a function from Koin
Trong định nghĩa lớp, nó tuân theo nguyên tắc tương tự, nó xác định nơi cung cấp một số chức năng, nhưng nó có thể tham chiếu đến bất kỳ tập hợp phương thức / thuộc tính nào, không chỉ get và set.
class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface
Đoạn mã này có nội dung: 'Tôi là lớp MyClass và tôi cung cấp các chức năng của giao diện SomeInterface được cung cấp bởi SomeImplementation. Tôi sẽ tự mình triển khai SomeOtherInterface (điều đó là ngầm, vì vậy không by
có). '
Cú pháp là:
val/var <property name>: <Type> by <expression>.
Biểu thức sau bởi là đại biểu
nếu chúng ta cố gắng truy cập giá trị của thuộc tính p , nói cách khác, nếu chúng ta gọi phương thức get () của thuộc tính p , thì phương thức getValue () của cá thể Delegate sẽ được gọi.
Nếu chúng ta cố gắng đặt giá trị của thuộc tính p , nói cách khác, nếu chúng ta gọi phương thức set () của thuộc tính p , thì phương thức setValue () của cá thể Delegate sẽ được gọi.
Ủy quyền tài sản:
import kotlin.reflect.KProperty
class Delegate {
// for get() method, ref - a reference to the object from
// which property is read. prop - property
operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
// for set() method, 'v' stores the assigned value
operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
println("value = $v")
}
}
object SampleBy {
var s: String by Delegate() // delegation for property
@JvmStatic fun main(args: Array<String>) {
println(s)
s = "textB"
}
}
Kết quả:
textA
value = textB
Ủy nhiệm cho lớp:
interface BaseInterface {
val value: String
fun f()
}
class ClassA: BaseInterface {
override val value = "property from ClassA"
override fun f() { println("fun from ClassA") }
}
// The ClassB can implement the BaseInterface by delegating all public
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val classB = ClassB(ClassA())
println(classB.value)
classB.f()
}
}
Kết quả:
property from ClassA
fun from ClassA
Ủy quyền cho các tham số:
// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
val name: String by mapA
val age: Int by mapA
var address: String by mapB
var id: Long by mapB
}
object SampleBy {
@JvmStatic fun main(args: Array<String>) {
val user = User(mapOf("name" to "John", "age" to 30),
mutableMapOf("address" to "city, street", "id" to 5000L))
println("name: ${user.name}; age: ${user.age}; " +
"address: ${user.address}; id: ${user.id}")
}
}
Kết quả:
name: John; age: 30; address: city, street; id: 5000