Co robi słowo kluczowe „by” w Kotlinie?

Odpowiedzi:

76

W referencji Kotlin znajdziesz dwa zastosowania by, z których pierwszym są właściwości delegowane, które są zastosowane powyżej:

Istnieją pewne typowe rodzaje właściwości, które chociaż możemy zaimplementować je ręcznie za każdym razem, gdy ich potrzebujemy, byłoby bardzo fajnie zaimplementować je raz na zawsze i umieścić w bibliotece. Przykłady obejmują leniwe właściwości: wartość jest obliczana tylko przy pierwszym dostępie, obserwowalne właściwości: słuchacze są powiadamiani o zmianach tej właściwości, przechowując właściwości na mapie, a nie w osobnych polach.

Tutaj delegujesz metodę pobierającą / ustawiającą do innej klasy, która wykonuje pracę i może zawierać wspólny kod. Jako kolejny przykład, niektóre wtryskiwacze zależności dla Kotlin obsługują ten model, delegując metodę pobierającą do otrzymywania wartości z rejestru instancji zarządzanych przez silnik iniekcji zależności.

I Interfejs / klasa delegacja jest inne zastosowanie:

Wzorzec delegowania okazał się dobrą alternatywą dla dziedziczenia implementacji, a Kotlin obsługuje go natywnie, wymagając zerowego kodu standardowego. Klasa Derived może dziedziczyć z interfejsu Base i delegować wszystkie swoje metody publiczne do określonego obiektu

Tutaj możesz delegować interfejs do innej implementacji, więc klasa implementująca musi tylko przesłonić to, co chce zmienić, podczas gdy pozostałe metody delegują z powrotem do pełniejszej implementacji.

Przykładem na żywo byłyby kolekcje Klutter Readonly / Immutable, w których po prostu delegują określony interfejs kolekcji do innej klasy, a następnie zastępują wszystko, co musi być inne w implementacji tylko do odczytu. Oszczędność pracy bez konieczności ręcznego delegowania wszystkich pozostałych metod.

Oba są objęte odniesieniem do języka Kotlin , zacznij tam od podstawowych tematów języka.

Jayson Minard
źródło
93

Krótko mówiąc, możesz zrozumieć bysłowo kluczowe dostarczone przez .

Z punktu widzenia konsumenta własności valjest to coś, co ma getter (get) i varjest czymś, co ma getter i setter (get, set). Dla każdegovar właściwości istnieje domyślny dostawca metod pobierania i ustawiania, których nie musimy jawnie określać.

Ale używając bysłowa kluczowego, stwierdzasz, że ten getter / getter & setter jest udostępniony gdzie indziej (tj. Został delegowany). Jest dostarczana przez funkcję, która jest później by.

Więc zamiast używać tej wbudowanej metody get and set, delegujesz to zadanie do jakiejś jawnej funkcji.

Bardzo częstym przykładem jest by lazyleniwe ładowanie właściwości. Ponadto, jeśli używasz biblioteki iniekcji zależności, takiej jak Koin, zobaczysz wiele właściwości zdefiniowanych w następujący sposób:

var myRepository: MyRepository by inject()  //inject is a function from Koin

W definicji klasy kieruje się tą samą zasadą, definiuje, gdzie jest dostarczana jakaś funkcja, ale może odnosić się do dowolnego zestawu metod / właściwości, a nie tylko do pobierania i ustawiania.

class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface

Ten kod mówi: „Jestem klasą MyClass i oferuję funkcje interfejsu SomeInterface, które są dostarczane przez SomeImplementation. Sam zaimplementuję SomeOtherInterface (to niejawne, więc nie byma). '

daneejela
źródło
23

wprowadź opis obrazu tutaj

Składnia jest następująca:

val/var <property name>: <Type> by <expression>. 

Wyrażenie po by to delegat

jeśli spróbujemy uzyskać dostęp do wartości właściwości p , innymi słowy, jeśli wywołamy metodę get () właściwości p , metodę getValue () metody Delegate wywoływana jest instancji .

Jeśli spróbujemy ustawić wartość właściwości p , innymi słowy, jeśli wywołamy metodę set () właściwości p , wywoływana jest metoda setValue () instancji Delegate .

oiyio
źródło
7

Delegacja do mienia:

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"
    }
}

Wynik:

textA
value = textB

Delegacja na zajęcia:

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()
    }
}

Wynik:

property from ClassA
fun from ClassA

Delegacja parametrów:

// 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}")
    }
}

Wynik:

name: John; age: 30; address: city, street; id: 5000
alexrnov
źródło