Home > Article > System Tutorial > In-depth analysis of the use of Kotlin functions and functional programming principles
Introduction | This article mainly introduces the usage of Kotlin functions and some of my understanding of functional programming. And will make some comparisons with Python and C. |
Since Google’s father announced Kotlin as his godson, Kotlin has been very popular in major communities.
If you know nothing about Kotlin syntax, it is recommended to read the official documentation or the Chinese website (https://www.kotlincn.net/docs/reference/) before reading this article for a deeper understanding.
The following is the definition of functional programming from Wikipedia:
Functional programming (English: functional programming), also known as functional programming, is a programming paradigm that treats computer operations as mathematical function calculations and avoids the use of program states and easy change object. The most important foundation of functional programming languages is lambda calculus. And the function of lambda calculus can accept functions as input (arguments) and output (outgoing value).
The following is the definition of higher-order functions:
In mathematics and computer science, a higher-order function is a function that meets at least one of the following conditions: accepts one or more functions as input and outputs a function
It is not difficult to infer that the most important foundation of functional programming is higher-order functions. That is, the support function can accept functions as inputs (arguments) and outputs (outgoing values).
As a first-class citizen in Kotlin, functions can be used as input and output of functions like other objects. This is the point that Java programmers find the biggest change and the most difficult to understand when they switch to Kotlin. If you have learned Python or C 11 before this may be easier for you. This is why this article mainly introduces Kotlin functions and functional programming.
Kotlin functionsThe following is the general function definition in Kotlin. Different from Java, the function parameters are placed last, and the return value type is placed last. The function body can be assigned to the function definition using the equal sign, and the equality of functions and variables can also be seen here.
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
In addition, Kotlin also supports function default parameters, extended functions, and infix expressions. The following is a simple example:
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 }
Functions that support default parameters can reduce function overloading.
There is no method in the String object to determine whether it is a letter. In Java, we usually define some Utils methods, while in Kotlin, we can define class extension functions.
The second example is to define an extension function for the Int class, and the extension function is expressed as an infix expression, giving developers the right to define similar keywords.
For example, we can create a map object like this:
val kv = mapOf("a" to 1, "b" to 2)
The to here is an infix expression, defined as follows:
public infix fun<A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
Pair is an object stored in Map, so you can also create it like this
val kv = mapOf(Pair("a", 1), Pair("b", 2))
In Python, if we want the function to return multiple values, we can return a tuple. Kotlin can also achieve similar functions based on the destructuring principle:
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) }
Please check the official documentation for how custom objects support destructuring. Map supports destructuring, so it can be traversed as follows:
for ((k, v) in map) { print("$k -> $v, ") }Higher-order functions and Lambda expressions
"Lambda expression" (lambda expression) is an anonymous function. Lambda expression is named based on the lambda calculus in mathematics. It directly corresponds to the lambda abstraction (lambda abstraction). It is an anonymous function, that is, it has no function name. The function. Lambda expressions can represent closures (note that they are different from the traditional mathematical sense).
Lambda expression 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 is relatively simple as a strongly typed language.
We can use a lambda expression like this:
fun main(args: Array) { val sumLambda = {a: Int, b: Int -> a + b} sumLambda(1, 2) }
It can be called using () like a function. In kotlin, operators can be overloaded. The () operator corresponds to the overloaded function invoke() of the class.
You can also define a variable like this:
val numFun: (a: Int, b: Int) -> Int
It is not an ordinary variable, it must point to a function, and the function signature must be consistent:
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 }
You can see that this variable can be equal to a lambda expression, another lambda expression variable, or an ordinary function, but you need to add (::) before the function name to obtain the function reference.
This is similar to the function pointer in C. However, in Python you can directly use the function name as a function reference. The following is an example of a C function pointer:
#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; }
Back to Kotlin, we can also pass one function to another function, such as:
//函数参数 fun doMap(list: List, function: (it: T) -> Any) { for (item in list) { function(item) } }
The first parameter is a List, and the second parameter is a function. The purpose is to execute the second function once for each element in the List. How to use it:
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 }
The second parameter is passed directly into a lambda expression. Of course, a function reference can also be passed in:
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 }
The effect is the same as the above code.
Using function pointers in C can achieve similar effects:
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); } }
Back to Kotlin again, if the function is the last one in the parameter list as an input parameter, you can also do this and write it directly within the curly brackets:
fun main(args: Array) { log { sum(1,2) } } fun log(function: () -> T) { val result = function() println("result -> $result") }
Is it a bit like the way gradle configuration files are written, so Kotlin can easily write domain-specific languages (DSL)
In addition, Kotlin also supports local functions and functions as return values, see the following 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作为一种强类型的现代化语言可以在保证稳定性的同时极大地提高开发者的开发效率。
The above is the detailed content of In-depth analysis of the use of Kotlin functions and functional programming principles. For more information, please follow other related articles on the PHP Chinese website!