跳转至

函数

1. 函数声明

// 声明一个函数
fn 函数名[捕获列表](参数列表) -> 返回类型;
  • 使用 fn 关键字声明函数。
  • 函数名:函数的标识符,用于在程序中调用该函数。
  • 捕获列表:可选项,指定函数中使用的外部变量的捕获方式。
  • 参数列表:可选项,包含函数的输入参数列表。
  • 返回类型:可选项,指定函数返回值的类型。

2. 函数定义

// 定义一个函数
fn 函数名[捕获列表](参数列表) -> 返回类型 {函数体}
  • 使用 fn 关键字定义函数。
  • 函数名、捕获列表、参数列表和返回类型的含义同函数声明。
  • 函数体:包含了函数的实际实现代码。

3. 单语句函数定义

// 定义一个单语句的函数
fn 函数名[捕获列表](参数列表) = 表达式;
  • 适用于只包含一条语句的函数,可以将函数体直接定义为一个表达式。
  • 表达式的计算结果将作为函数的返回值。

4. Lambda 表达式

// 定义一个 lambda 表达式
fn [捕获列表](参数列表) -> 返回类型 {函数体}
  • 可以直接定义匿名函数,称为 Lambda 表达式。
  • 不需要指定函数名,直接使用捕获列表、参数列表、返回类型和函数体定义 Lambda 函数。

5. 返回类型推断

  • 当函数体中所有 return 处的类型一致时,可以省略返回类型。
  • 若函数体中没有 return 语句,则返回类型推断为 void

6. 捕获列表

  • 捕获列表用于指定函数中引用外部变量的方式。
  • 可以省略捕获列表,默认为引用捕获所有外部变量。
  • 支持引用捕获和值捕获两种方式。

7. 参数列表

  • 参数列表用于指定函数的输入参数。
  • 可以省略参数列表,表示函数没有参数。
  • 当函数没有参数时,参数列表可以是 (),但不能像 C 语言那样写作 (void)

示例

fn add(int a, int b) {
  return a + b;
}

fn main {
  return add(1, -1);
}

调用简写

对于没有参数的函数,可以直接使用函数名来调用。

如果有以下函数:

fn rand() {
    @static
    int seed = 1;
    seed = seed * 114514 + 1919810;
    return seed;
}

我们就可以:

println(rand());
println(rand);

对于单个参数的函数,我们可以省略括号:

println("Hello world!");
println "Hello world!";

规范

我们明确:一个函数只应该做一件事情,这样可以使代码更加清晰。

函数一般不超过 20 行语句,超过的话应该考虑拆分。

函数尽量不依赖全局状态,这样可以使函数更加独立,也便于进行单元测试。

函数的参数应该尽量少,大多数不超过 3 个,少数可以达到 6 个,超过的话应该考虑拆分。
对于输入状态特别多的函数,应当使用结构体引用传参。

函数的参数应该尽量避免使用未进行限制的指针,除非有必要。