Kotlin语法基础篇三:函数

前言:

前两篇文章介绍了Kotlin中的基本数据类型属性和控制流。本篇文章我们将介绍Kotlin中比较重要的一个知识点:函数。对于函数,我想每个开发同学都不会陌生。善于将复杂的逻辑拆分成多个功能函数,将对我们代码的可读性和可维护性会有很大的帮助。而将多个复杂的逻辑放在同一个方法中,可能会让代码变得十分臃肿。下面让我们开始本篇文章的学习。

1.函数的声明

在Kotlin中我们用关键字fun来声明一个函数。一个简单的函数声明如下:

kotlin 复制代码
fun sum(left: Int, right: Int): Int {
        return left + right
}

关键字fun后面紧跟着函数名,通常函数名都是以这个函数实现的功能来命名的。函数名后紧跟着小括号(),定义该函数所需要的参数。即name:type。

多个参数用逗号隔开(name:type, name:type)。如果不需要参数,直接用()即可。如果该函数需要返回值则在()后面添加 :type。花括号{ }则代表这个函数的方法体或者说是这个函数的作用域。

2.函数的默认参数

通常在Java中函数我们称之为方法,相比较Java语言,Kotlin中的函数允许有参数默认值。而允许方法的参数可以拥有默认值,可以减少方法的重载(方法名相同,方法的参数类型和个数不同,我们称之为方法的重载)。如下函数的定义:

kotlin 复制代码
fun sum(left: Int, right: Int): Int {
        return left + right
}

// right参数具有默认值0
fun sum(left: Int, center: Int, right: Int = 0): Int {
        return left +center + right
}

当我们给sum函数的参数right添加了默认值以后。在函数调用的地方,我们可以选择性的传或者不传这个参数。

kotlin 复制代码
fun main() {
    sum(0, 10)
    sum(0, 10, 15)
}

fun sum(left: Int, center: Int, right: Int = 0): Int {
    return left +center + right
}

善于使用函数参数的默认值,在实际开发过程中,可以减少像Java语言中的方法重载。

3.具名参数

当我们调用一个拥有众多参数的函数时,参数类型和参数名匹配起来比较麻烦时。具名参数的使用就变得很有意义。使用具名参数可以不用考虑参数在函数中声明的顺序,使用propertyName = propertyValue的方式传入参数。假设我们有如下拥有多个参数的函数fold:

kotlin 复制代码
fun main() {
    fold(right = false, center = "center", left = 0, isEmpty = false)
}

fun fold(left: Int, center: String, right: Boolean, isEmpty: Boolean) {
    // ...省略逻辑
}

fold函数拥有4个参数,当我们在main函数中使用具名参数的方式调用fold函数,我们无需再考虑函数参数在声明时的位置,只要将所有的参数具名传入即可。当然在实际开发的过程中,一个复杂函数的参数远不与此。

4.函数的默认返回值Unit

当一个函数没有返回值时,它将拥有一个默认的返回值类型Unit。通常情况我们都会省略它。如下示例,我们将fold函数的返回值显示的声明成Unit

kotlin 复制代码
fun fold(initValue: Int):Unit {
    // ...省略逻辑
    return Unit
}

// 省略Unit
fun fold(initValue: Int) {
    // ...省略逻辑
    return 
}

返回时,我们可以直接使用return,也可以显示的加上Unit返回值类型。

5.单函数表达式

在上一篇文章属性和控制流中我们介绍到,当if或者when表达式的分支块中仅有一行表达式时,我们可以省略分支块的花括号。而Kotlin中的函数亦是如此。当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可:

kotlin 复制代码
fun sum(left: Int, right: Int): Int = left + right 

// Kotlin编译器可以推断出函数的返回值类型,可省略函数的返回值类型
fun sum(left: Int, right: Int) = left + right 

既然if或者when也可以作为单个表达式,那么我们也可以将一个函数用=连接一个if或者when的表达式。

kotlin 复制代码
fun isEmpty(str:String) = if(str.length == 0) true else false

// 示例代码
fun findNum(num:Int) = when(num) {
    1001 -> 0
    1002 -> 1
    else -> -1
}

6.可变数量的参数

在Java中我们使用propertyType... propertyName的方式来声明一个可变数量的参数:

typescript 复制代码
private void sum(Integer... value) {
        // ...
}

而在Kotlin中我们使用关键字vararg来声明可变数量的参数。

kotlin 复制代码
fun main() {
    sum(1, 2, 3)
}

fun sum(vararg value:Int) {
    for(i in value) {
        println("i = $i")
    }
}

// 输出
i = 1
i = 2
i = 3

7.中缀表示法

在Kotlin中使用infix关键字修饰的函数可以使用中缀表示法,忽略该函数调用时的点和括号。该函数必须满足如下条件:

  • 用infix修饰的函数有且只能有一个参数
  • 必须是成员函数或者扩展函数(关于扩展函数后面会详细讲解)
  • 不能接受vararg声明的可变数量的参数

典型的应用,我们可以看Kotlin中给我们提供的Tuples.kt中的数据类Pair:

kotlin 复制代码
public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable 
// ...

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

// ...

由上面的代码中我们可以看到数据类Pair有使用infix修饰的扩展函数to -> A.to(that: B)。下面我们来看一下在实际开发中的使用:

kotlin 复制代码
fun main() {
    val pair = 20 to "age"
    println("pair = $pair")
}

// 输出
pair = (20, age)

中缀表示法可以让我们的函数调用像阅读英文一样的优雅。使用A to B的方式创建了一个Pair对象,省略了调用函数时的点和括号。下面我们使用infix关键字来实现一个我们自己的定义的函数:

kotlin 复制代码
infix fun <T> Collection<T>.has(item: T) = if (item in this) true else false

fun main() {
    val languageList = arrayListOf("kotlin", "ios", "android")
    if (languageList has "test") {
        println("There is this language")
    } else {
        println("There is no such language")
    }
}

// 输出
There is no such language

8.函数作用域

1.在Kotlin中函数可以在文件顶层声明 。不需要像Java那样要创建一个类来保存一个函数。对与在文件顶层声明的函数默认情况下,我们可以在当前文件所在的项目中任意地方访问,除非你将函数显示的加上private访问修饰符。选中当前项目,右击鼠标或者触摸板。New -> Kotlin Class/File,在弹出的选择框中,我们选择File,声明一个Fun.kt的文件。

kotlin 复制代码
// 当前项目中可以调用
fun sum(left: Int, right: Int): Int {
    return left + right
}

// 当前文件中可以电泳
private fun fold() {
    println("fold called")
}

2.成员函数。

在类内部或者对象内部创建的函数我们称之为成员函数,以点表示法调用。

kotlin 复制代码
class Student {
    fun study() {
        println("I enjoy learning")
    }
}

fun main() {
    Student().study()
}

3.局部函数。(在Kotlin中支持一个函数嵌套另外一个函数)

在函数内部声明一个函数,我们就称这个函数为局部函数。如下示例,我们在main函数的内部声明了一个getMax函数。

kotlin 复制代码
fun main() {
    val a = 100
    val b = 100
    
    // 局部函数
    fun getMax() :Int {
        return if(a > b) {
            println("a = $a")
            a
        } else {
            println("b = $b")
            b
        }
    }

    println("${getMax()}")
}

局部函数可以访问外部函数声明的属性。

9.泛型函数

在Kotlin中我们通常在关键字fun之后紧<T>跟来声明一个泛型函数。(大写字母放在<>中,T是习惯性写法,也可以用别的大写字母表示),如下:

kotlin 复制代码
fun <T> getData(data:T) { 
    println("data = $data")
}

我们也可以将声明的泛型类型作为函数的返回值:

kotlin 复制代码
fun <T> getData(data:T) :T {
    println("data = $data")
    return data
}

关于Kotlin中泛型的使用我们会在后续的文章中详细介绍。

总结

到这里关于Kotlin中函数的介绍我们就写完了,下篇文章我们将详细介绍Kotlin中的高阶函数和Lambda表达式,我们下期再见。

相关推荐
安卓理事人12 分钟前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学1 小时前
Android M3U8视频播放器
android·音视频
q***57742 小时前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober2 小时前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿3 小时前
关于ObjectAnimator
android
zhangphil4 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我5 小时前
从头写一个自己的app
android·前端·flutter
lichong9516 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
用户69371750013846 小时前
14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)
android·后端·kotlin
火柴就是我7 小时前
NekoBoxForAndroid 编译libcore.aar
android