跳到主要内容

函数

函数是组织和重用代码的基本单元。本章将详细介绍 Sii 2 中函数的定义、调用、参数传递和返回值处理。

函数基础

函数定义

函数使用 func 关键字定义,基本语法如下:

func 函数名(参数列表): 返回类型 {
函数体
back 返回值; // 如果有返回值
}

简单函数示例

// 无参数、无返回值
func greet(): void {
sii.io.print("Hello, World!");
}

// 有参数、有返回值
func add(a: int, b: int): int {
back a + b;
}

// 有参数、无返回值
func printSum(a: int, b: int): void {
let sum: int = a + b;
sii.io.print("Sum: " + sum.toString());
}

函数调用

函数定义后,可以通过函数名和参数列表调用:

// 调用无返回值函数
greet();

// 调用有返回值函数
let result: int = add(3, 5); // result = 8

// 调用函数但不使用返回值
printSum(10, 20);

函数参数

参数声明

函数参数必须明确指定类型:

func calculate(a: int, b: int, operation: string): int {
if (operation == "add") {
back a + b;
} else if (operation == "subtract") {
back a - b;
} else {
back 0;
}
}

多个参数

函数可以有多个参数,用逗号分隔:

func createUser(name: string, age: int, email: string, isActive: bool): void {
sii.io.print("Creating user: " + name);
sii.io.print("Age: " + age.toString());
sii.io.print("Email: " + email);
sii.io.print("Active: " + isActive.toString());
}

参数类型

参数可以是任何类型:

// 基础类型参数
func processNumber(n: int): void { }

func processString(s: string): void { }

func processBoolean(b: bool): void { }

// 数组参数
func processArray(numbers: arr): void { }

// 对象参数
func processObject(data: obj): void { }

返回值

使用 back 关键字

函数使用 back 关键字返回值:

func getGreeting(): string {
back "Hello, World!";
}

func getMax(a: int, b: int): int {
if (a > b) {
back a;
} else {
back b;
}
}

void 返回类型

没有返回值的函数使用 void 作为返回类型:

func printMessage(msg: string): void {
sii.io.print(msg);
// 不需要 back 语句
}

多个返回点

函数可以有多个返回点:

func findValue(numbers: arr<int>, target: int): int {
forloop (let i: int = 0; i < numbers.length(); i.getUp(1)) {
if (numbers[i] == target) {
back i; // 找到后立即返回
}
}
back -1; // 未找到返回 -1
}

函数类型

纯函数

纯函数是指给定相同输入总是返回相同输出的函数,且没有副作用:

// 纯函数示例
func square(x: int): int {
back x * x;
}

func multiply(a: int, b: int): int {
back a * b;
}

有副作用的函数

有副作用的函数会修改外部状态或执行 I/O 操作:

let counter: int = 0;

func increment(): void {
counter = counter + 1; // 修改外部变量
}

func logMessage(msg: string): void {
sii.io.print(msg); // I/O 操作
}

递归函数

函数可以调用自身,实现递归:

// 计算阶乘
func factorial(n: int): int {
if (n <= 1) {
back 1;
}
back n * factorial(n - 1);
}

// 计算斐波那契数列
func fibonacci(n: int): int {
if (n <= 1) {
back n;
}
back fibonacci(n - 1) + fibonacci(n - 2);
}

递归注意事项

  • 基准情况:必须有一个或多个基准情况,避免无限递归
  • 递归深度:注意递归深度,避免栈溢出
  • 性能:某些递归可以用迭代优化

函数作用域

局部变量

函数内部定义的变量只在函数内部可见:

func example(): void {
let local: int = 10; // 局部变量
sii.io.print(local.toString());
}
// local 在这里不可访问

访问外部变量

函数可以访问外部作用域的变量:

let global: int = 100;

func accessGlobal(): void {
sii.io.print(global.toString()); // 可以访问全局变量
global = 200; // 可以修改全局变量
}

变量遮蔽

局部变量可以遮蔽外部同名变量:

let x: int = 10;

func test(): void {
let x: int = 20; // 遮蔽外部变量 x
sii.io.print(x.toString()); // 输出 20
}

函数最佳实践

1. 单一职责

每个函数应该只做一件事:

// 好的设计
func calculateTotal(items: arr): int {
let total: int = 0;
forloop (let i: int = 0; i < items.length(); i.getUp(1)) {
total = total + items[i];
}
back total;
}

// 不好的设计:函数做了太多事情
func processOrder(order: obj): void {
// 验证订单
// 计算总价
// 更新库存
// 发送邮件
// ...
}

2. 有意义的函数名

函数名应该清楚表达函数的功能:

// 好的命名
func calculateTax(amount: int): int { }
func validateEmail(email: string): bool { }
func getUserById(id: int): obj { }

// 不好的命名
func calc(x: int): int { }
func check(s: string): bool { }
func get(id: int): obj { }

3. 参数数量

避免参数过多,通常不超过 3-5 个:

// 好的设计:参数较少
func createUser(name: string, email: string): void { }

// 不好的设计:参数过多
func createUser(name: string, email: string, age: int, phone: string, address: string, city: string, country: string): void { }

// 改进:使用对象参数
func createUser(userData: obj): void { }

4. 返回值一致性

保持返回值的类型和含义一致:

// 好的设计:返回值含义明确
func findUser(id: int): obj | void {
// 找到返回对象,未找到返回 void
}

// 不好的设计:返回值含义不明确
func findUser(id: int): int {
// 返回什么?用户对象?ID?状态码?
}

5. 错误处理

考虑函数可能失败的情况:

func divide(a: int, b: int): int | void {
if (b == 0) {
sii.io.print("Error: Division by zero");
back; // 返回 void 表示失败
}
back a / b;
}

函数示例

示例 1:数学运算函数

func add(a: int, b: int): int {
back a + b;
}

func subtract(a: int, b: int): int {
back a - b;
}

func multiply(a: int, b: int): int {
back a * b;
}

func divide(a: int, b: int): int | void {
if (b == 0) {
sii.io.print("Error: Cannot divide by zero");
back;
}
back a / b;
}

func power(base: int, exponent: int): int {
let result: int = 1;
forloop (let i: int = 0; i < exponent; i.getUp(1)) {
result = result * base;
}
back result;
}

示例 2:字符串处理函数

func reverseString(s: string): string {
let reversed: string = "";
// 假设有 length() 和 charAt() 方法
forloop (let i: int = s.length() - 1; i >= 0; i.toDn(1)) {
// reversed = reversed + s.charAt(i);
}
back reversed;
}

func capitalize(s: string): string {
if (s.length() == 0) {
back s;
}
// 假设有字符操作方法
// let first: str = s.charAt(0).toUpperCase();
// let rest: string = s.substring(1);
// back first + rest;
back s; // 占位
}

示例 3:数组操作函数

func findMax(numbers: arr<int>): int | void {
if (numbers.length() == 0) {
back;
}
let max: int = numbers[0];
forloop (let i: int = 1; i < numbers.length(); i.getUp(1)) {
if (numbers[i] > max) {
max = numbers[i];
}
}
back max;
}

func sumArray(numbers: arr<int>): int {
let sum: int = 0;
forloop (let i: int = 0; i < numbers.length(); i.getUp(1)) {
sum = sum + numbers[i];
}
back sum;
}

func contains(numbers: arr<int>, value: int): bool {
forloop (let i: int = 0; i < numbers.length(); i.getUp(1)) {
if (numbers[i] == value) {
back true;
}
}
back false;
}

小结

本章介绍了 Sii 2 中函数的所有重要概念:

  • 函数定义:使用 func 关键字
  • 参数传递:必须明确指定参数类型
  • 返回值:使用 back 关键字返回
  • 函数类型:纯函数和有副作用的函数
  • 递归:函数可以调用自身
  • 作用域:局部变量和外部变量访问
  • 最佳实践:编写清晰、可维护的函数

下一章我们将学习控制流,掌握条件语句、循环语句和跳转语句的使用。