Maison >Tutoriel système >Linux >Analyse approfondie de l'utilisation des fonctions Kotlin et des principes de programmation fonctionnelle

Analyse approfondie de l'utilisation des fonctions Kotlin et des principes de programmation fonctionnelle

WBOY
WBOYavant
2023-12-29 14:27:191376parcourir
Présentation Cet article présente principalement l'utilisation des fonctions Kotlin et une partie de ma compréhension de la programmation fonctionnelle. Et fera quelques comparaisons avec Python et C++.

Depuis que le père de Google a annoncé Kotlin comme son filleul, Kotlin est très populaire dans les grandes communautés.
Si vous ne connaissez rien à la syntaxe Kotlin, il est recommandé de lire la documentation officielle ou le site chinois (https://www.kotlincn.net/docs/reference/) avant de lire cet article pour une compréhension plus approfondie.

Voici la définition de la programmation fonctionnelle de Wikipédia :

La programmation fonctionnelle (anglais : programmation fonctionnelle), également connue sous le nom de programmation fonctionnelle, est un paradigme de programmation qui traite les opérations informatiques comme des calculs de fonctions mathématiques et évite l'utilisation d'états de programme et d'objets volatils. Le fondement le plus important des langages de programmation fonctionnels est le calcul lambda. Et la fonction de calcul lambda peut accepter des fonctions comme entrée (arguments) et sortie (valeur sortante).

Voici la définition des fonctions d'ordre supérieur :

En mathématiques et en informatique, une fonction d'ordre supérieur est une fonction qui remplit au moins une des conditions suivantes : accepte une ou plusieurs fonctions en entrée et génère une fonction

Il n'est pas difficile de déduire que le fondement le plus important de la programmation fonctionnelle réside dans les fonctions d'ordre supérieur. Autrement dit, la fonction de support peut accepter des fonctions comme entrées (arguments) et sorties (valeurs sortantes).

En tant que citoyen de premier ordre dans Kotlin, les fonctions peuvent être utilisées comme entrée et sortie de fonctions comme d'autres objets. C'est le point sur lequel les programmeurs Java trouvent le plus grand changement et le plus difficile à comprendre lorsqu'ils passent à Kotlin. Si vous avez déjà appris Python ou C++11, cela peut être plus facile pour vous. C'est pourquoi cet article présente principalement les fonctions Kotlin et la programmation fonctionnelle.

Fonctions Kotlin

Ce qui suit est la définition générale de la fonction dans Kotlin. La différence avec Java est que les paramètres de la fonction sont placés en dernier et le type de valeur de retour est placé en dernier. Le corps de la fonction peut être attribué à la définition de la fonction à l'aide du signe égal, et l'égalité des fonctions et des variables peut également être vue ici.

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

De plus, Kotlin prend également en charge les paramètres par défaut des fonctions, les fonctions étendues et les expressions infixes :

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
}

Les fonctions prenant en charge les paramètres par défaut peuvent réduire la surcharge des fonctions.

Il n'y a pas de méthode dans l'objet String pour déterminer s'il s'agit d'une lettre. En Java, nous définissons généralement certaines méthodes Utils, tandis qu'en Kotlin, nous pouvons définir des fonctions d'extension de classe.
Le deuxième exemple consiste à définir une fonction d'extension pour la classe Int, et la fonction d'extension est exprimée sous la forme d'une expression infixe, donnant aux développeurs le droit de définir des mots-clés similaires.

Par exemple, nous pouvons créer un objet cartographique comme celui-ci :

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

To voici une expression infixe, définie comme suit :

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

Pair est un objet stocké dans Map, vous pouvez donc également le créer comme ceci

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

En Python, si nous voulons que la fonction renvoie plusieurs valeurs, nous pouvons renvoyer un tuple. Kotlin peut également réaliser des fonctions similaires basées sur le principe de déstructuration :

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

Veuillez consulter la documentation officielle pour savoir comment les objets personnalisés prennent en charge la déstructuration, afin qu'elle puisse être parcourue comme suit :

for ((k, v) in map) {
    print("$k -> $v, ")
}
Fonctions d'ordre supérieur et expressions Lambda

"Expression lambda" (expression lambda) est une fonction anonyme. L'expression lambda est nommée sur la base du calcul lambda en mathématiques. Elle correspond directement à l'abstraction lambda (abstraction lambda). un nom de fonction. Les expressions lambda peuvent représenter des fermetures (notez qu'elles sont différentes du sens mathématique traditionnel).

Expressions Lambda en Python :

add = lambda x, y:x+y

lambda en C++ :

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

lambda à Kotlin :

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

Kotlin est relativement simple en tant que langage fortement typé.

Nous pouvons utiliser une expression lambda comme celle-ci :

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

Il peut être appelé en utilisant () comme une fonction. Dans kotlin, les opérateurs peuvent être surchargés. L'opérateur () correspond à la fonction surchargée Ensure() de la classe.

Vous pouvez également définir une variable comme celle-ci :

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

Ce n'est pas une variable ordinaire, elle doit pointer vers une fonction, et la signature de la fonction doit être cohérente :

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
}

Vous pouvez voir que cette variable peut être égale à une expression lambda, à une autre variable d'expression lambda ou à une fonction ordinaire, mais vous devez ajouter (::) avant le nom de la fonction pour obtenir la référence de la fonction.

Ceci est similaire au pointeur de fonction en C++. Cependant, en Python, vous pouvez utiliser directement le nom de la fonction comme référence de fonction. Voici un exemple de pointeur de fonction C++ :

#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;
}

De retour dans Kotlin, on peut aussi passer une fonction à une autre fonction, comme par exemple :

//函数参数
fun  doMap(list: List, function: (it: T) -> Any) {
    for (item in list) {
        function(item)
    }
}

Le premier paramètre est une liste et le deuxième paramètre est une fonction. Le but est d'exécuter la deuxième fonction une fois pour chaque élément de la liste. Comment utiliser :

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
}

Le deuxième paramètre est passé directement dans une expression lambda. Bien entendu, une référence de fonction peut également être transmise :

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

L'effet est le même que le code ci-dessus.

Un effet similaire peut être obtenu en utilisant des pointeurs de fonction en C++ :

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

Retour à Kotlin, si la fonction est la dernière de la liste des paramètres en tant que paramètre d'entrée, vous pouvez également le faire et l'écrire directement entre accolades :

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

fun  log(function: () -> T) {
    val result = function()
    println("result -> $result")
}

N'est-ce pas un peu comme la façon dont les fichiers de configuration Gradle sont écrits, donc Kotlin peut facilement écrire des langages spécifiques à un domaine (DSL)

De plus, Kotlin prend également en charge les fonctions locales et les fonctions comme valeurs de retour, voir le code suivant :

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作为一种强类型的现代化语言可以在保证稳定性的同时极大地提高开发者的开发效率。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer