Heim  >  Artikel  >  System-Tutorial  >  Eingehende Analyse der Verwendung von Kotlin-Funktionen und funktionaler Programmierprinzipien

Eingehende Analyse der Verwendung von Kotlin-Funktionen und funktionaler Programmierprinzipien

WBOY
WBOYnach vorne
2023-12-29 14:27:191330Durchsuche
Einführung Dieser Artikel stellt hauptsächlich die Verwendung von Kotlin-Funktionen und einige meiner Kenntnisse der funktionalen Programmierung vor. Und ich werde einige Vergleiche mit Python und C++ anstellen.

Seit Googles Vater Kotlin als seinen Patensohn bekannt gegeben hat, erfreut sich Kotlin in großen Gemeinden großer Beliebtheit.
Wenn Sie nichts über die Kotlin-Syntax wissen, wird empfohlen, vor dem Lesen dieses Artikels die offizielle Dokumentation oder die chinesische Website (https://www.kotlincn.net/docs/reference/) zu lesen, um ein tieferes Verständnis zu erhalten.

Hier ist die Definition von funktionaler Programmierung aus Wikipedia:

Funktionale Programmierung (englisch: Functional Programming), auch als funktionale Programmierung bekannt, ist ein Programmierparadigma, das Computeroperationen als mathematische Funktionsberechnungen behandelt und die Verwendung von Programmzuständen und flüchtigen Objekten vermeidet. Die wichtigste Grundlage funktionaler Programmiersprachen ist die Lambda-Kalküle. Und die Funktion der Lambda-Rechnung kann Funktionen als Eingabe (Argumente) und Ausgabe (ausgehender Wert) akzeptieren.

Das Folgende ist die Definition von Funktionen höherer Ordnung:

In der Mathematik und Informatik ist eine Funktion höherer Ordnung eine Funktion, die mindestens eine der folgenden Bedingungen erfüllt: eine oder mehrere Funktionen als Eingabe akzeptiert und eine Funktion ausgibt

Es ist nicht schwer zu schließen, dass die wichtigste Grundlage der funktionalen Programmierung Funktionen höherer Ordnung sind. Das heißt, die Unterstützungsfunktion kann Funktionen als Eingaben (Argumente) und Ausgaben (ausgehende Werte) akzeptieren.

Als erstklassiger Bürger in Kotlin können Funktionen wie andere Objekte als Eingabe und Ausgabe von Funktionen verwendet werden. Dies ist der Punkt, den Java-Programmierer beim Wechsel zu Kotlin als die größte Änderung empfinden und am schwersten zu verstehen. Wenn Sie bereits Python oder C++11 gelernt haben, ist dies möglicherweise einfacher für Sie. Aus diesem Grund werden in diesem Artikel hauptsächlich Kotlin-Funktionen und funktionale Programmierung vorgestellt.

Kotlin-Funktionen

Das Folgende ist die allgemeine Funktionsdefinition in Kotlin. Der Unterschied zu Java besteht darin, dass die Funktionsparameter an letzter Stelle stehen und der Rückgabewerttyp an letzter Stelle steht. Über das Gleichheitszeichen lässt sich der Funktionskörper der Funktionsdefinition zuordnen, auch hier ist die Gleichheit von Funktionen und Variablen erkennbar.

fun main(args: Array) {
    var s = sum(1,2)
    var m = multi(2,3)
    var x = maxOf(3,4)
}

fun sum(a: Int, b: Int): Int {
    return a + b
}

fun multi(a: Int, b: Int): Int = a * b

fun maxOf(a: Int, b: Int): Int = if (a > b) a else b

Darüber hinaus unterstützt Kotlin auch Funktionsstandardparameter, erweiterte Funktionen und Infix-Ausdrücke. Hier ist ein einfaches Beispiel:

fun main(args: Array) {
    isBiggerThan(2)
    isBiggerThan(2, 5)
    var s = "a".isLetter()
    var a = 1 add 2
}

fun isBiggerThan(a: Int, b: Int = 0) {
    return a > b
}

//拓展函数
fun String.isLetter(): Boolean {
    return matches(Regex("^[a-z|A-Z]$"))
}

//拓展函数,中缀表达式
infix fun Int.add(x: Int): Int {
    return this + x
}

Funktionen, die Standardparameter unterstützen, können die Funktionsüberlastung reduzieren.

Es gibt keine Methode, um festzustellen, ob es sich um einen Buchstaben im String-Objekt handelt. In Java definieren wir normalerweise einige Utils-Methoden, während wir in Kotlin Erweiterungsfunktionen der Klasse definieren können.
Das zweite Beispiel besteht darin, eine Erweiterungsfunktion für die Int-Klasse zu definieren. Die Erweiterungsfunktion wird als Infix-Ausdruck ausgedrückt, wodurch Entwickler das Recht erhalten, ähnliche Schlüsselwörter zu definieren.

Zum Beispiel können wir ein Kartenobjekt wie folgt erstellen:

val kv = mapOf("a" to 1, "b" to 2)

Hier ist ein Infix-Ausdruck, der wie folgt definiert ist:

public infix fun<A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

Pair ist ein in Map gespeichertes Objekt, daher können Sie es auch so erstellen

val kv = mapOf(Pair("a", 1), Pair("b", 2))

Wenn wir in Python möchten, dass eine Funktion mehrere Werte zurückgibt, können wir mit Kotlin auch ähnliche Funktionen basierend auf dem Destrukturierungsprinzip erreichen:

fun main(args: Array) {
    val (index, count) = findWhere("abcabcabcabc", 'c')
}

fun findWhere(str: String, findChar: Char): Pair<Int, Int> {
    var index = -1
    var count = 0
    for ((i, v) in str.withIndex()) {
        if (v == findChar) {
            if (index == -1) {
                index = i
            }
            ++count
        }
    }
    return Pair(index, count)
}

Bitte lesen Sie in der offiziellen Dokumentation nach, wie benutzerdefinierte Objekte die Destrukturierung unterstützen, damit sie wie folgt durchlaufen werden kann:

for ((k, v) in map) {
    print("$k -> $v, ")
}
Funktionen höherer Ordnung und Lambda-Ausdrücke

„Lambda-Ausdruck“ (Lambda-Ausdruck) ist eine anonyme Funktion, die auf der Lambda-Abstraktion (Lambda-Abstraktion) basiert ein Funktionsname. Lambda-Ausdrücke können Abschlüsse darstellen (beachten Sie, dass sie sich vom traditionellen mathematischen Sinn unterscheiden).

Lambda-Ausdrücke in Python:

add = lambda x, y:x+y

lambda in C++:

[](int x, int y) -> int{ return x + y; }

Lambda in Kotlin:

var add = {x: Int, y: Int -> x + y}

Kotlin ist als stark typisierte Sprache relativ einfach.

Wir können einen Lambda-Ausdruck wie diesen verwenden:

fun main(args: Array) {
val sumLambda = {a: Int, b: Int -> a + b}
sumLambda(1, 2)
}

Es kann mit () wie eine Funktion aufgerufen werden. In Kotlin können Operatoren überladen werden. Der ()-Operator entspricht der überladenen Funktion invoke() der Klasse.

Sie können auch eine Variable wie diese definieren:

val numFun: (a: Int, b: Int) -> Int

Es handelt sich nicht um eine gewöhnliche Variable, sie muss auf eine Funktion verweisen und die Funktionssignatur muss konsistent sein:

fun main(args: Array) {
    val sumLambda = {a: Int, b: Int -> a + b}
    var numFun: (a: Int, b: Int) -> Int
    numFun = {a: Int, b: Int -> a + b}
    numFun = sumLambda
    numFun = ::sum
    numFun(1,2)
}

fun sum(a: Int, b: Int): Int {
    return a + b
}

Sie können sehen, dass diese Variable einem Lambda-Ausdruck, einer anderen Lambda-Ausdrucksvariablen oder einer gewöhnlichen Funktion entsprechen kann, Sie müssen jedoch (::) vor dem Funktionsnamen hinzufügen, um die Funktionsreferenz zu erhalten.

Dies ähnelt dem Funktionszeiger in C++. In Python können Sie jedoch den Funktionsnamen direkt als Funktionsreferenz verwenden. Das Folgende ist ein Beispiel für einen C++-Funktionszeiger

#include 

using namespace std;

void swap(int &x, int &y);

int main(int arg, char* args[]) {
	int x = 10;
	int y = 20;

	void (*methodPtr)(int &x, int &y);//声明一个函数指针
	methodPtr = &swap; //函数指针赋值
	methodPtr = swap;//取地址符可省略,效果和上面一致
	methodPtr(x, y); //像给函数起了一个别名,可以直接使用()调用
	cout << "x:" << x << " y:" << y << endl; //x:20 y:10
}

void swap(int &x, int &y) {
	int tmp = x;
	x = y;
	y = tmp;
}

Zurück in Kotlin können wir auch eine Funktion an eine andere Funktion übergeben, wie zum Beispiel:

//函数参数
fun  doMap(list: List, function: (it: T) -> Any) {
    for (item in list) {
        function(item)
    }
}
Der erste Parameter ist eine Liste und der zweite Parameter ist eine Funktion. Der Zweck besteht darin, die zweite Funktion einmal für jedes Element in der Liste auszuführen. Anwendung:

val strList = listOf("h" ,"e", "1", "a", "b", "2", " ", "", "c", "5", "7", "F")
doMap(strList, {item ->print("item: ${upperLetter(item)}, ") })

fun upperLetter(item: String): String {
    if (item.isLetter()) {
        return item.toUpperCase()
    }
    return item
}
Der zweite Parameter wird direkt in einen Lambda-Ausdruck übergeben. Natürlich kann auch eine Funktionsreferenz übergeben werden:

val strList = listOf("h" ,"e", "1", "a", "b", "2", " ", "", "c", "5", "7", "F")
doMap(strList, ::printUpperLetter)

fun printUpperLetter(item: String) {
    print("item: ${upperLetter(item)}, ")
}

fun upperLetter(item: String): String {
    if (item.isLetter()) {
        return item.toUpperCase()
    }
    return item
}
Der Effekt ist der gleiche wie beim obigen Code.

Ein ähnlicher Effekt kann mit Funktionszeigern in C++ erzielt werden:

using namespace std;

void mMap(vector list, void (*fun)(int item));

int main(int arg, char* args[]) {
	vector list = {2,3,4,3,2,1,2};
	mMap(list, [](int item) -> void { cout << item << endl; });
}

void mMap(vector list, void (*fun)(int item)) {
	for(int it : list) {
	    fun(it);
	}
}

Zurück zu Kotlin: Wenn die Funktion als Eingabeparameter die letzte in der Parameterliste ist, können Sie dies auch tun und direkt in die geschweiften Klammern schreiben:

fun main(args: Array) {
    log { sum(1,2) }
}

fun  log(function: () -> T) {
    val result = function()
    println("result -> $result")
}
Ist es nicht ein bisschen wie die Art und Weise, wie Gradle-Konfigurationsdateien geschrieben werden, sodass Kotlin problemlos domänenspezifische Sprachen (DSL) schreiben kann

?

Darüber hinaus unterstützt Kotlin auch lokale Funktionen und Funktionen als Rückgabewerte, siehe folgenden Code:

fun main(args: Array) {
    val addResult = lateAdd(2, 4)
    addResult()
}
//局部函数,函数引用
fun lateAdd(a: Int, b: Int): Function0 {
    fun add(): Int {
        return a + b
    }
    return ::add
}

在lateAdd内部定义了一个局部函数,最后返回了该局部函数的引用,对结果使用()操作符拿到最终的结果,达到延迟计算的目的。

函数作为一级公民当然可以像普通对象一样放进map中,比如下面这样:

val funs = mapOf("sum" to ::sum)
val mapFun = funs["sum"]
if (mapFun != null) {
   val result = mapFun(1,2)
   println("sum result -> $result")
}

fun sum(a: Int, b: Int): Int {
    return a + b
}

将一个函数引用作为value放进了map中,取出来之后使用()操作符调用,可以简化一些if,else的场景。

基于以上函数式编程的特性,Kotlin可以像RxJava一样很方便的进行相应式编程,比如:

fun printUpperLetter(list: List) {
    list
            .filter (fun(item):Boolean {
                return item.isNotEmpty()
            })
            .filter { item -> item.isNotBlank()}
            .filter {
                item ->
                if (item.isNullOrEmpty()) {
                    return@filter false
                }
                return@filter item.matches(Regex("^[a-z|A-Z]$"))
            }
            .filter { it.isLetter() }
            .map(String::toUpperCase)
            .sortedBy { it }
            .forEach { print("$it, ") }
    println()
}

上面的代码只是做演示,并无实际意义。具体语法请查看官方文档。

我相信Kotlin作为一种强类型的现代化语言可以在保证稳定性的同时极大地提高开发者的开发效率。

Das obige ist der detaillierte Inhalt vonEingehende Analyse der Verwendung von Kotlin-Funktionen und funktionaler Programmierprinzipien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:linuxprobe.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen