带你踏入kotlin大门(三)|基本功_函数篇

简介: 本文给讲述 kotlin 中的 头等公民 ,函数。

前置知识

  • Java 编程基础
  • 已学习 Kotlin 变量知识

前言

上一篇文章 我们讲述了 kotlin 中变量与 Java 中的变量的不同,同时也简单说明 kotlin 中的类型推导机制、val 修饰的变量是 引用不可变而非对象不可变 以及我们需要优先使用 val 这些知识。

本文给讲述 kotlin 中的 头等公民函数

函数

kotlin 中的函数与 Java 中的不同

在本系列开篇文章中有提到,kotlin 在兼顾 Java 规范的同时,又做了很多拓展;其中,最重要的拓展就是:kotlin 是支持部分函数式特性的

函数式编程具有五个鲜明的特点。

1、函数是"第一等公民" 所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

2、只用"表达式",不用"语句" "表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

3、没有"副作用" 所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

4、不修改状态 上一点已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。

5、引用透明性 函数程序通常还加强引用透明性,即如果提供同样的输入,那么函数总是返回同样的结果。就是说,表达式的值不依赖于可以改变值的全局状态。

函数式编程的特点

kotlin 中函数式的特性在接下来的学习中,我们会逐步学习到。下面我们先来看一下,在 kotlin 中使用函数与 Java 有何不同。

//Java
public int numsAdd(int x ,int y){
    return x+y;
}
复制代码

上面 Java 中的函数形式大家都很熟悉了,那么在 kotlin 中,这段函数该如何写呢?

//kotlin
public fun numsAdd(x: Int ,y: Int): Int{
    return x+y
}
复制代码

上述的 kotlin 代码,是将 java 代码按照原来的逻辑,一点都不变的翻译而来的。但事实上,这却并不符合 kotlin 的代码特性。我们先对这段代码进行解释,后面再将其修改为符合 kotlin 特性的代码。

kotlin 中的函数有以下几个基本特性

  1. funfunction 的意思,代表这是一个功能,意思是这是一个方法,一个函数。在 kotlin 中,每一个 方法 都要使用 fun 来修饰。
  2. 方法中返回值的声明,和前文类型声明一样,采用 <name>:<object> 形式,在参数括号后用:接上类型即可。若无函数类型声明,则返回 Unit 类型,效果与 Java 中的 void 函数一样。
  3. 参数声明也是使用  <name>:<object>  的形式;若无参数,使用空括号即可。

事实上,若按照逻辑从 Java 中翻译过来,上一段代码中的 public 应该删除。这是为什么呢?

因为 Java 中的可见性修饰符 public ,在 Kotlin 中是不必声明的,因为 kotlin 中默认修饰符就是 public,所以我们可以将上述代码更改为如下。

//kotlin
fun numsAdd(x: Int ,y: Int): Int{
    return x+y
}
复制代码

同时,这里附上修饰符对比表格供大家参考。

修饰符 Java Kotlin
public 所有类可见 所有类可见**(默认)**
private 当前类可见 当前类可见
protected 当前类、子类、同一包路径下的类可见 当前类、子类可见
default 同一包路径下的类可见**(默认)**
internal 同一模块中的类可见

前面我们还说到,kotlin 是支持函数式的,那如何把这段代码 函数式 化呢?我们可以使用一个 = 来代替代码块函数体以及返回值,这种单行的表达称之为 表达式函数体

//函数化
fun numsAdd(x: Int ,y: Int): Int = x+y
复制代码

同时,基于 Kotlin 的类型推导机制,我们可以把函数返回值的类型声明去掉,更改为如下形式

//函数化+类型推导
fun numsAdd(x: Int ,y: Int) = x+y
复制代码

上述代码该到这里,就是妥妥的 Kotlin 风格的代码了。我们前后对照,是不是代码量比Java要少得多呢,但是其魅力远不止于此,我们继续探索学习吧!

Kotlin 中函数的类型推导不是全局的

上述的 Kotlin 代码中,我们最后一步更改是利用了 Kotlin 的类型推导功能,但是我在这里要告诉你的是,Kotlin 的类型推导不是全局的

这是什么意思呢?何为不是全局的?我们用上述代码举一个例子,相信你很快就能明白。假设 Kotlin 的类型推导是全局的,那么当我们没将代码函数法,且我们想利用它的 类型推导特性 的时候,我们自然而然会写出如下的代码。

//假设支持全局类型推导
fun numsAdd(x: Int ,y: Int){
    return x+y
}
复制代码

但事与愿违,上述代码报错了。原因是类型缺失,意思是我们需要加上函数返回值的类型。可见,Kotlin 的类型推导并非那么智能,它的类型推导不是全局的

1.webp.jpg

那么,是不是只要我们使用到 函数表达式 ,Kotlin 就一定能进行类型推导了呢?非也,我们可以看下面的这段代码。

//未作声明,会报错
fun recursion(n: Int) = if (n == 0) 1 else recursion(n-1)
复制代码

1.webp.jpg

这段代码依旧报错,因为递归的存在,它还是无法推导出函数的返回值类型。这是由于 Kotlin 继承和支持子类型的特性,导致类型推导不够聪明。

所以,遇到这些情况,我们做以下显式的类型声明就好了

//做显式声明,代码成功
fun recursion(n: Int): Int = if (n == 0) 1 else recursion(n-1)
复制代码

那么,关于类型声明,我们该如何选择是否显式声明呢?

  • 如果它是一个函数的参数?
    必须使用
  • 如果它是一个非表达式定义的函数?
    除了返回 Unit,其他情况必须使用
  • 如果它是一个递归函数?
    必须使用
  • 如果它是一个公有方法,且具有返回值?
    建议使用,可提高代码可阅读性以及稳定性

Lambda语法

Lambda语法,事实上在 Java 中已经出现了,当我们使用 JDK 1.8 以上,就可以在 Java 中使用了。

由于Kotlin 中的 lambda 语法使用起来是有很多技巧,且具有很多高级用法以及知识,所以在这里就只做和 Java 中 lambda 的一些简单区别展示。

首先我们看一下 ,lambda 是什么?

接下来谈众所周知的 Lambda 表达式。它是推动 Java 8 发布的最重要新特性。是继泛型(Generics)和注解(Annotation)以来最大的变化。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。让 java 也能支持简单的函数式编程

Lambda 表达式是一个匿名函数(初步这么理解就可,实际上是不一样的),java 8 允许把函数作为参数传递进方法中。

在 Java 中,能够使用 函数式API/lambda 的条件是,对应要表达的匿名内部类,这一个类是 单抽象方法接口 。意思是,这个类是接口,且接口里面只有一个抽象方法。

我们以常用的 button 设置点击的监听方法为例,看一下 Java 中的 lambda 实现。其中,把参数简写为 v ,并使用 -> 指向函数体

//包含匿名内部类
getBinding().homeTextViewFollower.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        ...
    }
});
//匿名内部类变为lambda形式
getBinding().homeTextViewFollower.setOnClickListener(v -> {
    ...
});
复制代码

1.webp.jpg

同时,我们可以看到,该内部类就是 单抽象方法接口

以上面代码为例,Kotlin 中使用 lambda 即为如下形式。由于参数只有一个,我们可以把其直接简写删除,且外层直接用 {} 表示,表明此处为 lambda 表达式。

getBinding().homeTextViewFollower.setOnClickListener{
    ...
}
复制代码

关于 lambda 表达式,先讲到这,后续更多的内容在后续文章中会逐步讲明。

如何传入函数作为参数

Kotlin 函数式的一大特点,就是支持在函数内写函数,或者是给函数传递函数,让函数成为第一等公民。

由于时间和篇幅原因,此处暂时不讲如何设置函数的参数可传入函数,只讲如何传入函数。关于如何设置函数参数可传入参数,我们后续讲到函数的高级应用时再说。下面的代码,可以实现向函数的参数中传入bind函数

val binding = holder.getBinding(RecyclerviewItemRankBinding::bind)
复制代码

我们传入函数,用的是 :: 这个符号,其表示将 RecyclerviewItemRankBinding 这个类中的 bind 函数传入,可以很好的实现复用和传递。

1.webp.jpg

同时,我们可以看一下 getBinding 这个函数的参数设计,但这里暂不做对应更多的解释。

@Suppress("UNCHECKED_CAST")
fun <VB : ViewBinding> BaseViewHolder.getBinding(bind: (View) -> VB): VB =
  itemView.getTag(Int.MIN_VALUE) as? VB ?: bind(itemView).also { itemView.setTag(Int.MIN_VALUE, it) }
复制代码

上述参考代码来自 CymChad/BaseRecyclerViewAdapterHelper: BRVAH:Powerful and flexible RecyclerAdapter (github.com)



相关文章
|
2月前
|
Kotlin
Kotlin中的函数分类(顶层、成员、局部、递归等)
Kotlin中的函数分类(顶层、成员、局部、递归等)
20 1
|
11天前
|
Java Android开发 开发者
Kotlin 循环与函数详解:高效编程指南
高效编程实践 • 避免不必要的循环 - 尽量使用集合操作如 map、filter 来减少显式的循环。 • 使用尾递归优化 - 对于需要大量递归的情况,考虑使用尾递归以优化性能。 • 内联函数 - 对于传递 Lambda 表达式的函数,使用 inline 关键字可以减少运行时开销。 通过上述指南,您应该能够更好地理解 Kotlin 中的循环和函数,并能够编写更加高效和简洁的代码。Kotlin 的设计哲学鼓励开发者编写易于理解和维护的代码,而掌握循环和函数是实现这一目标的关键步骤。 如果您想了解更多关于 Kotlin 的循环和函数的信息,以下是一些官方文档和资源,它们可以提供额外的参考
24 1
|
11天前
|
Java Kotlin
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用`for`循环结合`in`操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用`..`来定义一系列连续的值并进行迭代。此外,Kotlin支持通过`break`和`continue`控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,`myFunction(x: Int, y: Int) = x + y`简洁地定义了一个计算两数之和的函数。
26 1
|
27天前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
26 8
|
27天前
|
Swift iOS开发 Kotlin
苹果iOS新手开发之Swift中实现类似Kotlin的作用域函数
Swift可通过扩展实现类似Kotlin作用域函数效果。如自定义`let`, `run`, `with`, `apply`, `also`,增强代码可读性和简洁性。虽无直接内置支持,但利用Swift特性可达成相似功能。
36 7
|
1月前
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
37 6
|
2月前
|
Kotlin
Kotlin中的函数定义
Kotlin中的函数定义
15 4
|
2月前
|
Java Kotlin
Kotlin 中的 apply 函数详解
Kotlin 中的 apply 函数详解
194 0
|
2月前
|
设计模式 Java Kotlin
Kotlin 中的 run 函数详解
Kotlin 中的 run 函数详解
191 0
|
2月前
|
Java Kotlin
Kotlin 中的 with 函数简介
Kotlin 中的 with 函数简介
186 0