> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/programming-language/kotlin/shu-ju-lei-xing/han-shu-lei-xing.md).

# 函数类型

## 函数

Kotlin 中的函数使用`fun`关键字声明，函数名称的命名规则与变量一致：

```kotlin
fun double(x: Int): Int {
    return 2 * x
}
```

### 函数作为类型的表示

Kotlin 的函数类型是一种特殊的类型，它可以描述函数的类型信息，包括函数的参数和返回值类型。在 Kotlin 中，函数类型是以 `(参数类型) -> 返回值类型` 的形式来表示的。

例如，一个函数类型为 `(Int, String) -> Boolean` 的函数类型表示接收两个参数，一个为 Int 类型，一个为 String 类型，返回一个 Boolean 类型的值。

在 Kotlin 中，函数类型可以用作变量类型、参数类型、返回值类型、以及类型别名等。这使得函数可以像普通变量一样被传递、赋值、以及作为函数的参数和返回值使用。这种特性在函数式编程中非常重要。

同时，Kotlin 还提供了一种特殊的函数类型 `() -> Unit`，它表示不接收任何参数，也不返回任何值的函数类型，类似于 Java 中的 void 类型。

### 函数的参数

函数参数使用 Pascal 表示法定义，即 name: type。参数用逗号隔开。 每个参数必须有显式类型：

1. 有参函数定义：

   ```kotlin
   fun powerOf(number: Int, exponent: Int): Int { /*……*/ }
   ```
2. 无参函数定义：

   ```kotlin
   fun powerOf(): Int { /*……*/ }
   ```
3. 参数可以添加默认值：

   ```kotlin
   fun read(
       b: Array<Byte>, 
       off: Int = 0, 
       len: Int = b.size,
   ) { /*……*/ }
   ```
4. 如果从基类中覆盖一个有参的并且填写了默认值的方法，那么子类在覆盖此方法时的定义，必须从签名中省略默认参数值；也就是说，覆盖方法会沿用被覆盖方法的参数默认值：

   ```kotlin
   open class A {
       open fun foo(i: Int = 10) { /*……*/ }
   }

   class B : A() {
       override fun foo(i: Int) { /*……*/ }  // 不能有默认值
   }
   ```
5. 可变参数

   ```kotlin
   fun <T> asList(vararg ts: T): List<T> {
       val result = ArrayList<T>()
       for (t in ts) // ts is an Array
           result.add(t)
       return result
   }

   asList(1, 2, 3)
   // 或者使用伸展操作符，将数组展开
   val a = arrayOf(1, 2, 3)
   val list = asList(-1, 0, *a, 4)
   ```

### 函数的返回值

1. 无返回值函数

   ```kotlin
   // 无返回值函数可以使用 Unit 类型来表示，也可以省略返回值类型。
   fun printHello() {
       println("Hello")
   }

   fun printWorld(): Unit {
       println("World")
   }
   ```
2. 单返回值函数

   ```kotlin
   // 单个返回值函数可以使用任意类型来表示，如果没有显式指定返回值类型，则会根据函数体自动推断出返回值类型。
   fun add(a: Int, b: Int): Int {
       return a + b
   }

   fun sub(a: Int, b: Int) = a - b
   ```
3. 多返回值函数

   ```kotlin
   // Kotlin 中没有直接支持多个返回值的语法，但可以使用 Pair、Triple 等数据类来返回多个值。
   fun getPerson(): Pair<String, Int> {
       return Pair("Alice", 18)
   }

   fun getUser(): Triple<String, Int, String> {
       return Triple("Bob", 20, "male")
   }
   ```

### 函数的调用

1. 正常通过类型匹配调用

   ```kotlin
   fun foo(
       bar: Int = 0,
       baz: Int,
   ) : Int {
       println("bar=$bar baz=$baz")
       return bar + baz
   }
   // 正常通过类型匹配进行调用
   val r = foo(1, 2)
   ```
2. 函数参数中，如果每个参数都有默认值，那么可以省略函数参数，或者省略部分函数参数

   ```kotlin
   fun foo1(x: Int = 1, y: Int = 2) {}
   foo1()  
   foo2(1) // 传入x=1
   foo3(y = 1) // 传入y=1，x使用默认值，这里需要使用具名参数
   ```
3. 如果函数中有默认值的参数在无默认参数之后，这时候又不想传入默认值参数，就必须使用具名参数

   ```kotlin
   fun foo2(
       bar: Int = 0,
       baz: Int,
   ) : Int {
       println("bar=$bar baz=$baz")
       return bar + baz
   }
   foo2(baz = 2)
   ```
4. 同样的，如果所有没有默认值的参数都在前面，那么有默认值的参数都可以省略：

   ```kotlin
   fun reformat(
       str: String,
       normalizeCase: Boolean = true,
       upperCaseFirstLetter: Boolean = true,
       divideByCamelHumps: Boolean = false,
       wordSeparator: Char = ' ',
   ) {
   /*……*/
   }
   reformat('This is a long String!')
   ```

函数的调用，在没有具名参数的情况下，优先使用函数类型匹配函数。

### 局部函数

Kotlin 支持局部函数，即一个函数在另一个函数内部，局部函数可以访问外部函数（即闭包）的局部变量：

```kotlin
fun dfs(graph: Graph) {
    val visited = HashSet<Vertex>()
    fun dfs(current: Vertex) {
        if (!visited.add(current)) return
        for (v in current.neighbors)
            dfs(v)
    }

    dfs(graph.vertices[0])
}
```

### 匿名函数

```kotlin
val sum = fun(x: Int, y: Int): Int {
    return x + y
}
val s = sum(1, 2)
println(s)

// list的map方法，就可以传入一个匿名函数
val list = listOf(1, 2, 3, 4, 5)
val newList = list.map(fun(i): Int { return i * 2 })
```

## 闭包

```kotlin
fun returnFun(): () -> Int {
    var count = 0
    return { count++ }
}

fun main() {
    val function = returnFun()
    val function2 = returnFun()
    println(function()) // 0
    println(function()) // 1
    println(function()) // 2
    
    println(function2()) // 0
    println(function2()) // 1
    println(function2()) // 2
}
```

returnFun返回了一个函数，这个函数没有入参，返回值是Int。可以用变量接收它，还可以调用它。function和function2分别是创建的两个函数实例。 可以看到，每调用一次function()，count都会加一，说明count 被function持有了而且可以被修改。而function2和function的count是独立的，不是共享的。
