仓颉开发之——函数(6)

一 概述

  • 定义函数
  • 调用函数
  • 函数类型
  • 嵌套函数
  • Lambda表达式
  • 闭包
  • 函数语法糖调用
  • 函数重载
  • 操作符重载

二 定义函数

2.1 定义函数

1
2
3
func add(a: Int64, b: Int64): Int64 {
return a + b
}

说明:

  • 使用关键字func定义函数
  • func 之后依次是函数名、参数列表、可选的函数返回值类型、函数体

2.2 参数列表

1
2
3
func add(a!: Int64 = 1, b!: Int64 = 1): Int64 {
return a + b
}

说明:

  • 参数列表中的参数分为两类:非命名参数和命名参数
  • 非命名参数的定义方式是 p: T,其中 p 表示参数名,T 表示参数 p 的类型,参数名和其类型间使用冒号连接
  • 命名参数的定义方式是 p!: T,与非命名参数的不同是在参数名 p 之后多了一个 !
  • 命名参数还可以设置默认值,通过 p!: T = e 方式将参数 p 的默认值设置为表达式 e 的值

三 调用函数

3.1 非命名参数调用

1
2
3
4
5
6
7
8
9
10
func add(a: Int64, b: Int64) {
return a + b
}

main() {
let x = 1
let y = 2
let r = add(x, y)
println("The sum of x and y is ${r}")
}

执行结果

1
The sum of x and y is 3

3.2 命名参数调用

1
2
3
4
5
6
7
8
9
10
func add(a!: Int64, b!: Int64) {
return a + b
}

main() {
let x = 1
let y = 2
let r = add(b: y, a: x)
println("The sum of x and y is ${r}")
}

执行结果

1
The sum of x and y is 3

说明:

  • 命名参数调用时须知名参数

四 函数类型

4.1 概念

函数类型由函数的参数类型和返回类型组成,参数类型和返回类型之间使用 -> 连接

1
2
3
func hello(): Unit {
println("Hello!")
}

说明:

  • 上述示例定义了一个函数,函数名为 hello
  • 其类型是 () -> Unit,表示该函数没有参数,返回类型为 Unit

4.2 函数类型作为参数类型

1
2
3
4
5
6
7
8
9
10
11
12
func add(a: Int64, b: Int64): Int64 {
a + b
}

func returnAdd(): (Int64, Int64) -> Int64 {
add
}

main() {
var a = returnAdd()
println(a(1,2))
}

五 嵌套函数

5.1 概念

定义在源文件顶层的函数被称为全局函数。定义在函数体内的函数被称为嵌套函数

5.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func foo() {
func nestAdd(a: Int64, b: Int64) {
a + b + 3
}

println(nestAdd(1, 2)) // 6

return nestAdd
}

main() {
let f = foo()
let x = f(1, 2)
println("result: ${x}")
}

输出结果

1
2
6
result: 6

说明:定义f,f返回的结果为nestAdd,可以调用(Int64,Int64)->Int64

六 Lambda表达式

6.1 Lambda表达式定义

Lambda 表达式的语法为如下形式: { p1: T1, ..., pn: Tn => expressions | declarations }。

1
2
3
let f1 = { a: Int64, b: Int64 => a + b }

var display = { => println("Hello") } // Parameterless lambda expression.

说明:

  • Lambda 表达式不管有没有参数,都不可以省略 =>,除非其作为尾随 lambda

6.2 Lambda 表达式调用

1
2
3
4
5
6
7
8
//1-立即调用
let r1 = { a: Int64, b: Int64 => a + b }(1, 2) // r1 = 3
let r2 = { => 123 }() // r2 = 123
//2-变量名调用
func f() {
var g = { x: Int64 => println("x = ${x}") }
g(2)
}

七 闭包

7.1 概念

闭包就是能够读取其他函数内部变量的函数或函数或 lambda 和捕获的变量一起被称为一个闭包

7.2 其他

  • 变量捕获
  • 变量捕获规则

八 函数语法糖调用

8.1 尾随 lambda

1-说明

  • 当函数最后一个形参是函数类型,并且函数调用对应的实参是 lambda 时
  • 我们可以使用尾随 lambda 语法,将 lambda 放在函数调用的尾部,圆括号外面

2-示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func myIf(a: Bool, fn: () -> Int64) {
if(a) {
fn()
} else {
0
}
}

func test() {
myIf(true, { => 100 }) // General function call

myIf(true) { // Trailing closure call
100
}
}

8.2 Flow 表达式

流操作符包括两种:表示数据流向的中缀操作符 |> (称为 pipeline)和表示函数组合的中缀操作符 ~> (称为 composition)

1-Pipeline 表达式(e1 |> e2。等价于如下形式的语法糖:let v = e1; e2(v) )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func inc(x: Array<Int64>): Array<Int64> { // Increasing the value of each element in the array by '1'
let s = x.size
var i = 0
for (e in x where i < s) {
x[i] = e + 1
i++
}
x
}

func sum(y: Array<Int64>): Int64 { // Get the sum of elements in the array.
var s = 0
for (j in y) {
s += j
}
s
}

let arr: Array<Int64> = Array<Int64>([1, 3, 5])
let res = arr |> inc |> sum // res = 12

2-Composition 表达式(f ~> g。等价于如下形式: { x => g(f(x)) })

1
2
3
4
5
6
7
8
func f(x: Int64): Float64 {
Float64(x)
}
func g(x: Float64): Float64 {
x
}

var fg = f ~> g // The same as { x: Int64 => g(f(x)) }

8.3 变长参数

当形参最后一个非命名参数是 Array 类型时,实参中对应位置可以直接传入参数序列代替 Array

1
2
3
4
5
6
7
8
9
10
11
12
func sum(arr: Array<Int64>) {
var total = 0
for (x in arr) {
total += x
}
return total
}

main() {
println(sum())
println(sum(1, 2, 3))
}

九 函数重载

9.1 函数重载定义

  • 函数名相同,函数参数不同(是指参数个数不同,或者参数个数相同但参数类型不同)的两个函数构成重载
  • 对于两个同名泛型函数,如果重命名一个函数的泛型形参后,其非泛型部分与另一个函数的非泛型部分函数参数不同,则两个函数构成重载
  • 同一个类内的两个构造函数参数不同,构成重载
  • 同一个类内的主构造函数和 init 构造函数参数不同,构成重载
  • 两个函数定义在不同的作用域,在两个函数可见的作用域中构成重载。
  • 两个函数分别定义在父类和子类中,在两个函数可见的作用域中构成重载

9.2 函数重载决议

函数调用时,所有可被调用的函数(是指当前作用域可见且能通过类型检查的函数)构成候选集,候选集中有多个函数,究竟选择候选集中哪个函数,需要进行函数重载决议

十 操作符重载

10.1 可重载操作符

No 操作符 描述
1 () Function call
2 [] Indexing
3 ! NOT
4 - Negative
5 ** Power
6 * Multiply
7 / Divide
8 % Remainder
9 + Add
10 - Subtract

10.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
open class Point {
var x: Int64 = 0
var y: Int64 = 0
public init (a: Int64, b: Int64) {
x = a
y = b
}

public operator func -(): Point {
Point(-x, -y)
}
public operator func +(right: Point): Point {
Point(this.x + right.x, this.y + right.y)
}
}

十一 思维导图

十二 参考

  • 仓颉—函数
  • 仓颉语言入门教程