Kotlin-Differenzierungsanalyse, lassen, ausführen, mit, anwenden und auch

Die Scope-Funktion ist ein wichtiges Merkmal von Kotlin. Sie ist in die folgenden fünf Typen unterteilt: let , run , with , apply und also . Man kann sagen, dass die Arbeitsmethoden dieser fünf Funktionen sehr ähnlich sind, aber was wir verstehen müssen, ist Diese fünf Funktionsunterschiede ermöglichen eine bessere Nutzung in verschiedenen Szenarien. Nachdem Sie diesen Artikel gelesen haben, wissen Sie:

Was sind Bereichsfunktionen in Kotlin?

  • Die jeweiligen Rollen der fünf Scope-Funktionen let, run, with, apply und also;
  • Unterschiede zwischen 5 Arten von Bereichsfunktionen;
  • Wann und wo werden diese 5 Zielfernrohre verwendet?

Scope-Funktionen in Kotlin

Die Kotlin-Standardbibliothek enthält mehrere Funktionen, deren einziger Zweck darin besteht, Codeblöcke im Kontext von Objekten auszuführen. Wenn eine solche Funktion für ein Objekt aufgerufen und ein Lambda-Ausdruck bereitgestellt wird, bildet sie einen temporären Bereich. Innerhalb dieses Bereichs kann auf das Objekt ohne seinen Namen zugegriffen werden. Diese Funktionen werden Bereichsfunktionen genannt.

Einfach ausgedrückt dient die Scope-Funktion dazu, den Zugriff und die Bedienung eines Objekts zu erleichtern. Sie können Nullprüfungen durchführen, seine Eigenschaften ändern oder seinen Wert direkt zurückgeben. Der folgende Fall enthält eine detaillierte Beschreibung der Scope-Funktion. Veranschaulichen Sie .

Rollenpositionierung

2.1 lass

public inline fun <T, R> T.let(block: (T) -> R): R

Die let-Funktion ist eine Erweiterungsfunktion vom parametrisierten Typ T. Das Objekt kann dadurch innerhalb des let-Blocks referenziert werden. Der Rückgabewert ist die letzte Zeile des let-Blocks oder der angegebene Rückgabeausdruck.

Nehmen wir als Beispiel ein Book-Objekt. Die Klasse enthält den Namen und den Preis des Buches wie folgt:

class Book() {
    
    
    var name = "《数据结构》"
    var price = 60
    fun displayInfo() = print("Book name : $name and price : $price")
}
fun main(args: Array<String>) {
    
    
    val book = Book().let {
    
    
        it.name = "《计算机网络》"
        "This book is ${
      
      it.name}"
    }
    print(book)
}

Konsolenausgabe:

This book is 《计算机网络》

Im obigen Fall verwenden wir die Let-Scope-Funktion für das Book-Objekt, fügen dem letzten Satz des Funktionsblocks eine Zeile String-Code hinzu und drucken das Book-Objekt. Wir können sehen, dass das endgültige Ausgabeergebnis der Konsole die Zeichenfolge ist. Dieses Buch heißt „Computernetzwerke“.

Gemäß unseren Programmierideen muss beim Drucken eines Objekts die Ausgabe ein Objekt sein, aber nach Verwendung der let-Funktion ist die Ausgabe die letzte Zeichenfolge. Dies liegt an den Eigenschaften der Let-Funktion. Denn wenn in Kotlin die letzte Anweisung in einem Let-Block eine Nichtzuweisungsanweisung ist, handelt es sich standardmäßig um eine Return-Anweisung .

Was passiert also, wenn wir die letzte Anweisung im let-Block in eine Zuweisungsanweisung ändern?

fun main(args: Array<String>) {
    
    
    val book = Book().let {
    
    
        it.name = "《计算机网络》"
    }
    print(book)
}

Konsolenausgabe:

kotlin.Unit

Sie können sehen, dass wir den Namenswert des Book-Objekts zugewiesen und das Book-Objekt gedruckt haben, die endgültige Ausgabe der Konsole jedoch „kotlin.Unit“ war. Dies liegt daran, dass der letzte Satz des let-Funktionsblocks eine Zuweisungsanweisung ist. print behandelt es als Funktion.

  • Dies ist der erste Punkt der Charaktereinstellung: 1️⃣

Wenn die letzte Anweisung im let-Block eine Nichtzuweisungsanweisung ist, handelt es sich standardmäßig um eine Return-Anweisung. Andernfalls wird ein Unit-Typ zurückgegeben.

  • Schauen wir uns den zweiten Punkt von let an: 2️⃣ let kann für Nullsicherheitsüberprüfungen verwendet werden.

Um Operationen an einem Nicht-Null-Objekt auszuführen, verwenden Sie den Safe-Call-Operator?. und rufen Sie let auf, um die Operation in einem Lambda-Ausdruck auszuführen.

Die folgenden Fälle:

var name: String? = null
fun main(args: Array<String>) {
    
    
    val nameLength = name?.let {
    
    
        it.length
    } ?: "name为空时的值"
    print(nameLength)
}

Wir setzen „name“ auf eine nullbare Zeichenfolge und verwenden „name?.let“, um eine Nullbeurteilung durchzuführen. Nur wenn „name“ nicht null ist, kann die Logik in den „let“-Funktionsblock eintreten. Hier können wir den Vorteil des leeren Urteils vielleicht nicht erkennen, aber wenn Sie eine große Anzahl von Namensattributen schreiben müssen, können Sie feststellen, dass let schnell und prägnant ist.

  • Der dritte Punkt von let: 3️⃣

let arbeitet mit den Ergebnissen der Aufrufkette.

Diesbezüglich gibt das offizielle Tutorial einen Fall an, der hier direkt verwendet wird:

fun main(args: Array<String>) {
    
     
    val numbers = mutableListOf("One","Two","Three","Four","Five")
    val resultsList = numbers.map {
    
     it.length }.filter {
    
     it > 3 }
    print(resultsList)
}

Unser Ziel besteht darin, die Werte in der Array-Liste abzurufen, deren Länge größer als 3 ist. Da wir das Ergebnis ausdrucken müssen, speichern wir das Ergebnis in einer separaten Variablen und drucken es dann aus. Aber mit dem „let“-Operator können wir den Code wie folgt ändern:

fun main(args: Array<String>) {
    
    
    val numbers = mutableListOf("One","Two","Three","Four","Five")
    numbers.map {
    
     it.length }.filter {
    
     it > 3 }.let {
    
    
        print(it)
    }
}

Nach der Verwendung von let können Sie Werte mit einer Länge von mehr als 3 direkt in der Array-Liste drucken, wodurch der Schritt der Variablenzuweisung entfällt.

Darüber hinaus gibt es eine weitere Funktion der let-Funktion.

  • Der vierte Punkt von let: 4️⃣

let kann „It“ in einen lesbaren Lambda-Parameter umbenennen.
let verweist mithilfe des Schlüsselworts „It“ auf den Kontext des Objekts. Daher kann dieses „It“ in einen lesbaren Lambda-Parameter umbenannt werden

Benennen Sie es wie folgt in „Buchen“ um:

fun main(args: Array<String>) {
    
    
    val book = Book().let {
    
    book ->
        book.name = "《计算机网络》"
    }
    print(book)
}

2,2 laufen

Die run- Funktion verwendet dies als Kontextobjekt und ihre aufrufende Methode stimmt mit let überein.

  • Der erste Punkt: 1️⃣ Wenn der Lambda-Ausdruck sowohl die Objektinitialisierung als auch die Berechnung des Rückgabewerts enthält, ist run besser geeignet.

Was bedeutet das? Lassen Sie uns mit einem Fall sprechen:

fun main(args: Array<String>) {
    
    

    Book().run {
    
    
        name = "《计算机网络》"
        price = 30
        displayInfo()
    }
}

Konsolenausgabe:

Book name : 《计算机网络》 and price : 30

Was passiert mit dem Code mit derselben Funktion, wenn die Ausführungsfunktion nicht verwendet wird? Lass uns einen Blick darauf werfen:

fun main(args: Array<String>) {
    
    

    val book = Book()
    book.name = "《计算机网络》"
    book.price = 30
    book.displayInfo()
}

Konsolenausgabe:

Book name : 《计算机网络》 and price : 30

Das Ausgabeergebnis ist immer noch das gleiche, aber die Code-Einfachheit, die die Ausführungsfunktion mit sich bringt, ist bereits offensichtlich.

Schauen wir uns darüber hinaus weitere Vorteile der Run-Funktion an:

Durch einen Blick auf den Quellcode habe ich erfahren, dass es zwei Deklarationsmethoden für die Ausführungsfunktion gibt.

1. run ist wie let eine Erweiterungsfunktion von T;

inline fun <T, R> T.run(block: T.() -> R): R

2. Der zweite Lauf wird anders deklariert, es handelt sich nicht um eine Erweiterungsfunktion und es gibt keine Eingabewerte im Block, daher wird er nicht zum Übergeben von Objekten und zum Ändern der Art von Eigenschaften verwendet, sondern ermöglicht die Verwendung von Ausdrücken an beliebiger Stelle Sie brauchen sie. Sie können eine Anweisung ausführen.

inline fun <R> run(block: () -> R): R

Im Folgenden wird der Ausführungsfunktionsblock zum Ausführen der Methode anstelle einer Erweiterungsfunktion verwendet:

run {
    
    
        val book = Book()
        book.name = "《计算机网络》"
        book.price = 30
        book.displayInfo()
    }

2,3 mit

inline fun <T, R> with(receiver: T, block: T.() -> R): R

with ist keine Erweiterungsfunktion. Sie gibt einen Objektempfänger direkt ein. Wenn der Empfänger eingegeben wird, können die Eigenschaften des Empfängers geändert werden. Gleichzeitig macht es dasselbe wie run.

Oder liefern Sie ein Fallbeispiel:

fun main(args: Array<String>) {
    
    
    val book = Book()

    with(book) {
    
    
        name = "《计算机网络》"
        price = 40
    }
    print(book)
}

Nehmen wir das obige Beispiel: Wenn der Typ „with“ (T) in einem Parameterbuch übergeben wird, können Sie im Codeblock „with“ auf die Namens- und Preisattribute des Buches zugreifen und Änderungen vornehmen.

with verwendet ein Nicht-Null-Objekt. Wenn in einem Funktionsblock kein Rückgabewert erforderlich ist, können Sie with verwenden.

2.4 gelten

inline fun <T> T.apply(block: T.() -> Unit): T

apply ist eine Erweiterungsfunktion von T. Sie ähnelt etwas der run-Funktion. Sie bezieht sich auf den Kontext des Objekts als „this“ statt „it“ und bietet eine Null-Sicherheitsprüfung. Der Unterschied besteht darin, dass apply das nicht akzeptiert Der Rückgabewert im Funktionsblock und die Rückgabe ist ein eigenes Objekt vom Typ T.

fun main(args: Array<String>) {
    
    
    Book().apply {
    
    
        name = "《计算机网络》"
        price = 40

    }
    print(book)
}

Konsolenausgabe:

com.fuusy.kotlintest.Book@61bbe9ba

Die Funktionen let, with und run , die wir zuvor gesehen haben, geben alle R zurück. Wenden Sie sich jedoch auch unten an und schauen Sie sich die Rückgabe T an . Beispielsweise hat in let der Wert, der im Funktionsblock nicht zurückgegeben wird, am Ende den Typ Unit, in apply dagegen wird das Objekt selbst (T), wenn es schließlich zurückgegeben wird, vom Typ Book.

Die Apply-Funktion wird hauptsächlich zum Initialisieren oder Ändern eines Objekts verwendet, da sie dazu dient, sich selbst zurückzugeben, ohne die Funktion des Objekts zu verwenden.

2,5 ebenfalls

inline fun <T> T.also(block: (T) -> Unit): T

ist auch eine Erweiterungsfunktion von T. Der Rückgabewert ist derselbe wie bei apply, und T wird direkt zurückgegeben. Die Funktion „also“ wird ähnlich wie die Funktion „let“ verwendet. Sie verweist auf den Kontext des Objekts als „it“ statt „this“ und bietet Null-Sicherheitsüberprüfungen.

Da T als Eingabe für die Blockfunktion dient, können Sie mit T auch auf die Eigenschaften zugreifen. Daher auch bei Nichtverwendung oder Änderung der Objekteigenschaften verwenden.

fun main(args: Array<String>) {
    
    
    val book  = Book().also {
    
    
        it.name = "《计算机网络》"
        it.price = 40
    }
    print(book)
}

Konsolenausgabe:

com.fuusy.kotlintest.Book@61bbe9ba

Differenzierung

3.1 Lassen und laufen

let bezieht sich auf das Kontextobjekt als es, und run bezieht sich auf dieses;
run kann „this“ nicht in einen lesbaren Lambda-Parameter umbenennen, aber let kann „it“ in einen lesbaren Lambda-Parameter umbenennen. Sie können den Vorteil dieser Funktion erkennen, wenn let mehrfach verschachtelt ist.

3.2 mit & ausführen

Mit und run machen sie eigentlich dasselbe. Beide nennen das Kontextobjekt „this“, aber sie sind unterschiedlich. Schauen wir uns den Fall einmal an.

Verwenden Sie zunächst die with-Funktion:

fun main(args: Array<String>) {
    
    
    val book: Book? = null
    with(book){
    
    
        this?.name = "《计算机网络》"
        this?.price = 40
    }
    print(book)

}

Wir haben ein nullfähiges Objektbuch erstellt und die with-Funktion verwendet, um die Eigenschaften des Buchobjekts zu ändern. Der Code ist sehr intuitiv, daher ersetzen wir ihn durch „run“ und der Code ändert sich zu:

fun main(args: Array<String>) {
    
    
    val book: Book? = null
    book?.run{
    
    
        name = "《计算机网络》"
        price = 40
    }
    print(book)
}

Erstens lässt der Aufruf der Ausführungsfunktion die Referenz auf this weg und führt eine Nullsicherheitsprüfung auf der äußeren Ebene durch. Nur wenn sie nicht null ist, kann der Funktionsblock zum Betreiben des Buches eingegeben werden.

Im Vergleich zu with ist die Ausführungsfunktion einfacher und Nullsicherheitsprüfungen sind nicht so häufig wie bei.

3.3 Bewerben & lassen

apply akzeptiert den Rückgabewert im Funktionsblock nicht und gibt sein eigenes T-Typ-Objekt zurück, während let es zurückgeben kann.
Die Objektreferenz des Apply-Kontexts ist „this“ und let ist „it“.

Wann sollten Sie apply, with, let, also und run verwenden?

Zum Initialisieren eines Objekts oder Ändern der Eigenschaften eines Objekts können Sie „Apply“ verwenden,
wenn Sie das Objekt validieren, bevor Sie den Eigenschaften des empfangenden Objekts Daten zuweisen. Sie können es auch verwenden,
wenn das Objekt auf Null geprüft ist und um auf seine Eigenschaften zuzugreifen oder diese zu ändern. Sie können let verwenden,
wenn es sich um ein Nicht-Null-Objekt handelt. Wenn im Funktionsblock kein Wert zurückgegeben werden muss, können Sie with verwenden.
Wenn Sie einen bestimmten Wert berechnen oder den Umfang mehrerer lokaler Variablen einschränken möchten, Lauf verwenden.

Zusammenfassen

Das Obige sind die Funktionen und Verwendungsszenarien der Kotlin-Bereichsfunktionen. In der tatsächlichen Entwicklung von Android werden die fünf Funktionen sehr häufig verwendet. Während der Verwendung haben wir festgestellt, dass die Bereichsfunktion uns viel bringen kann, wenn die Codelogik klein ist des Codes. Einfachheit und Lesbarkeit, aber wenn die Logik komplex ist, verringert die Verwendung verschiedener Funktionen und mehrerer Überlagerungen die Lesbarkeit. Dies erfordert, dass wir ihre jeweiligen Eigenschaften unterscheiden, damit sie in geeigneten und komplexen Szenarien eingesetzt werden können.

Guess you like

Origin blog.csdn.net/u010274449/article/details/132358454