Kotlin从入门到“放弃”(二)——函数

简介: 写在开头 上一篇介绍了Kotlin的基本使用,发现这门语言主要还是面向函数进行编程,所以这一篇主要在函数方面介绍Kotlin。基本函数  Kotlin作为一个面向函数的编程语言,函数的使用自然是最基本的,上一篇的main函数就是函数式语言的体现。

写在开头

上一篇介绍了Kotlin的基本使用,发现这门语言主要还是面向函数进行编程,所以这一篇主要在函数方面介绍Kotlin。

基本函数

  Kotlin作为一个面向函数的编程语言,函数的使用自然是最基本的,上一篇的main函数就是函数式语言的体现。最简单的调用函数的方法如下:

fun main(vararg arg: String){
    println(add(1, 2))
}

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

  由上面的自定义函数add可知,函数的定义方式是fun <函数名>(<参数>)[: <返回类型>] { <代码块>},特别指出kotlin函数的返回类型如上面的add所示在参数后面添加表示,如果没有返回值的话可以不用写或者可以把Int换成Unit。当函数代码块中代码就是返回值就像add,可以直接写成单一表达式,如下。

fun add(a: Int, b: Int) = a + b

  再来说一下参数,Kotlin中的参数使用Pascal符号定义,参数与定义变量常量不同,必须指定类型。这一点毫无疑问与java相同,但与java相同的是kotlin函数参数可以有默认值,当该参数有默认值时调用处该参不是必传的,不传就是默认值,这就是kotlin中变相的函数重载。

fun main(vararg arg: String){
    println(add(1))
}
fun add(a: Int, b: Int = 5) = a + b

Lambda表达式

  Kotlin中支持并使用了大量的Lambda表达式,谷歌使用Kotlin作为Android开发的一个官方语言据说也是因为能够使用这个表达式(手动滑稽)。java也在jdk8之后支持了Lambda表达式(λ),先以java为例说明。
  λ表达式其实就是匿名函数在java中可以说是内部匿名类,一般语法是(参数)->{程序主体}。在java中能够作为λ表达式传入的一种形式就是函数式接口,函数式接口是只有一个抽象方法的接口,所以Runnable接口就是符合这么一个特性的可以使用λ表达式,它的源码如下:

public interface Runnable {
    public abstract void run();
}

  一般情况下在代码中新建一个线程是新建一个Thread实例,而Thread其中的一个构造函数参数就是Runnable,常见的代码是这样的:

Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("This is a new thread!");
            }
        });
thread.start();

  其中run方法没有参数,写成λ表达式是这个样子的:

Thread thread = new Thread(() -> System.out.println("THis is a new thread!"));
thread.start();

  可以看到代码量有了明显的缩减,这也是Lambda表达式的优势。在Kotlin中是这么使用这个表达式的呢,这里依然使用add函数表示,也是这个函数的又一种变形。

var add = {a: Int, b: Int -> a + b}
println(add(1, 2))

  这里输出的同样是1和2的和,一些和Lambda有关的内容可以参考细说Lambda表达式这篇文章。

一些高阶函数

  高阶函数其实是将函数作为参数或者返回值的一类函数,Kotlin官方文档对其有一部分介绍——高阶函数与Lambda,这里介绍一下几个高阶函数,首先是内置的集合操作类函数。

map和flatmap

  熟悉rxjava的话,应该会对这两个单词比较熟悉,map是一个集合映射成一个新集合

val list1 = listOf(1,2,3,4,5)
list1.map {
    it + 1
}.forEach {
    print("$it ")
}

  上面的代码有一个list1集合,使用map映射的功能对集合内的元素分别进行加1,最后输出的是“2 3 4 5 6 ”,中间的空格是输出的时候添加的。而flatmap的做的事情可能要更多点。

val list1 = listOf(1,2,3,4,5)
val list2 = listOf(2,3,4,5,6)
val list3 = arrayListOf(list1, list2)
list3.flatMap { it + 1 }.forEach { print(it) }

  这里的输出是1234561234561,可以看到flatmap可以将各个iterator打通成一个list。

reduce和fold

  reduce是规约fold是折叠,两者都是将一个集合根据一个规则返回一个最终结果,两者的使用也是非常相似。reduce和上面的map有着千丝万缕的联系,Hadoop中使用的MapReduce计算框架可以说这里的两个函数的意思差不多。而reduce在Kotlin中是怎么使用的呢,如果我们要对map那一小节中的list1进行求和就可以使用reduce。

list1.reduce { sum, i -> sum + i }

  可以看到reduce的Lambda表达式使用时有两个参数,从reduce的部分源码中可以看到第一个参数是每次的返回值也是最终的返回值,这里最后的结果是15。

public inline fun <S, T: S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {

  而fold与reduce的不同之处在于他有个初始值,也就是sum可以设定一个初始值,而reduce中的sum初始值是0。

public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {

  这样的化fold的使用就是如下这样的。

list1.fold(2){
    sum, i-> sum + i
}

复合函数

  其实这种函数的例子网上还是听常见的,这里的例子也是照搬一下网上的资源吧,只是做一下比较通俗的解释。对于这样一个数学公式:m(x)=f(g(x)),如果使用代码实现可能会直接想到其中一个函数调用另个函数的结果就可以实现,但是在Kotlin中给我们提供了函数的扩展,可以写成如下的形式。(如果是初学者看不懂也不要着急

val add = {a: Int -> a + 5}
val multiply = {a: Int -> a * 2}
val addAndMultiply = add addThen multiply
infix fun <P1, P2, R> Function1<P1, P2>.addThen(function: Function1<P2, R>): Function1<P1, R>{
    return fun(p1: P1): R{
        return function(this(p1))
    }
}

   ok,首先定义了两个函数add和multiply分别代表了g(x)和f(x),而addAndMultiply竟然是使用了已经定义好的这两个函数,是怎么做到的,那就要看定义的这个扩展函数addThen了。

  • infix关键字是Kotlin里面中缀表达式的意思,这样定义就可以像案例中用中缀的形式使两个函数结合,如果没有的化那只能是add.addThen(mutiply)了。
  • P1, P2, R相当于定义使用参数的类型,其实整个函数想表达的就是P1->P2->R简化成P1->R.
  • Funcion1,Kotlin提供了 Lambda表达式的函数表示,而且允许的最大入参N是22,也就是FunctionN最大是Function22,这里的add函数只有一个参数,所以这里是Function1
  • addThen在这里就是Function1的扩展函数,既然是“add addThen multiply”这样使用了,那它就是add的扩展函数。

  如果像下面这样变一下型,估计可以更好的理解一下其中的原理。

val add :Function1<Int, Int> = {a: Int -> a + 5}
val multiply: Function1<Int, Int> = {a: Int -> a * 2}

   其实add和multiply两个函数同样是Function1类型的有一个参数,也就解释通为什么可以像上面那样定义一个扩展函数了。最后说明一下addThen扩展函数是先运行它前面的,也就是add里面的逻辑,然后运行multiply中的,即 g(x) addThen f(x) = f(g(0))。

总结

  本篇写了一些Kotlin中的函数定义和使用,而且本片文章没有什么图片(因为是第一次使用markdown来写,还不顺手),继续记录自己的技术之旅。

目录
相关文章
|
11月前
|
Java Kotlin
开心档-软件开发入门之​Kotlin 基本数据类型​
开心档-软件开发入门之​Kotlin 基本数据类型​
21 0
|
11天前
|
安全 Java Android开发
Kotlin入门实用开发技巧与注意事项
本文源自公众号“AntDream”。Kotlin是由JetBrains开发的现代编程语言,自2017年成为Android官方开发语言后迅速流行。本文作者分享了Kotlin的实用技巧,包括变量声明、空安全、扩展函数等,帮助初学者避免常见问题。
42 15
|
3月前
|
Kotlin
Kotlin中的函数分类(顶层、成员、局部、递归等)
Kotlin中的函数分类(顶层、成员、局部、递归等)
|
24天前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
39 1
|
1月前
|
Java Android开发 开发者
Kotlin 循环与函数详解:高效编程指南
高效编程实践 • 避免不必要的循环 - 尽量使用集合操作如 map、filter 来减少显式的循环。 • 使用尾递归优化 - 对于需要大量递归的情况,考虑使用尾递归以优化性能。 • 内联函数 - 对于传递 Lambda 表达式的函数,使用 inline 关键字可以减少运行时开销。 通过上述指南,您应该能够更好地理解 Kotlin 中的循环和函数,并能够编写更加高效和简洁的代码。Kotlin 的设计哲学鼓励开发者编写易于理解和维护的代码,而掌握循环和函数是实现这一目标的关键步骤。 如果您想了解更多关于 Kotlin 的循环和函数的信息,以下是一些官方文档和资源,它们可以提供额外的参考
33 1
|
1月前
|
Java Kotlin
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用`for`循环结合`in`操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用`..`来定义一系列连续的值并进行迭代。此外,Kotlin支持通过`break`和`continue`控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,`myFunction(x: Int, y: Int) = x + y`简洁地定义了一个计算两数之和的函数。
39 1
|
2月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
40 8
|
2月前
|
Swift iOS开发 Kotlin
苹果iOS新手开发之Swift中实现类似Kotlin的作用域函数
Swift可通过扩展实现类似Kotlin作用域函数效果。如自定义`let`, `run`, `with`, `apply`, `also`,增强代码可读性和简洁性。虽无直接内置支持,但利用Swift特性可达成相似功能。
48 7
|
2月前
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
46 6
|
3月前
|
Kotlin
Kotlin中的函数定义
Kotlin中的函数定义