Skip to content

函数与方法

函数是 Targo 程序的基本构建块。本指南介绍如何定义和使用函数、方法、闭包以及 Targo 特有的功能。

函数声明

命名函数

使用 function 关键字声明函数:

typescript
// 基本函数
function add(a: int, b: int): int {
    return a + b;
}

// 无返回值函数
function greet(name: string): void {
    console.log(`Hello, ${name}!`);
}

// 调用函数
let sum = add(5, 3);  // 8
greet("Alice");       // "Hello, Alice!"

TypeScript 对比

语法与 TypeScript 完全相同,但类型必须使用 Go 的数值类型(int, float64 等)而非 number

箭头函数

箭头函数提供简洁的语法:

typescript
// 完整形式
let multiply = (a: int, b: int): int => {
    return a * b;
};

// 单表达式(隐式返回)
let square = (x: int): int => x * x;

// 类型推断(当上下文明确时)
let numbers: Array<int> = [1, 2, 3];
let doubled = numbers.map(x => x * 2);

函数表达式

typescript
// 函数表达式
let divide = function(a: float64, b: float64): float64 {
    if (b == 0) {
        panic("division by zero");
    }
    return a / b;
};

// 使用
let result = divide(10, 2);  // 5.0

变量初始化

Targo 要求所有变量必须显式初始化,这消除了意外使用零值的风险。

基本初始化

typescript
// ✅ 正确:带初始值
let count: int = 0;
let name: string = "Alice";
let isActive: bool = true;

// ✅ 正确:类型推断
let age = 25;           // 推断为 int
let message = "hello";  // 推断为 string

// ❌ 错误:未初始化
let x: int;             // 编译错误
let y: string;          // 编译错误

使用 zero() 获取零值

当需要类型的零值时,使用 zero<T>() 函数:

typescript
// 获取零值
let n = zero<int>();        // 0
let s = zero<string>();     // ""
let b = zero<bool>();       // false

// 结构体零值
class User {
    name: string;
    age: int;
}

let user = zero<User>();    // { name: "", age: 0 }

为什么需要显式初始化?

这一设计使代码意图更清晰:

  • let x = zero<int>() 明确表示"我需要零值"
  • 避免意外使用未初始化的变量
  • 与 TypeScript 的严格模式语义一致

函数参数

基本参数

typescript
// 单个参数
function double(x: int): int {
    return x * 2;
}

// 多个参数
function format(name: string, age: int): string {
    return `${name} is ${age} years old`;
}

// 不同类型参数
function calculate(a: float64, b: int, op: string): float64 {
    // ...
}

可选参数

使用 ? 标记可选参数:

typescript
function greet(name: string, greeting?: string): string {
    if (greeting != null) {
        return `${greeting}, ${name}`;
    }
    return `Hello, ${name}`;
}

// 调用
greet("Alice");              // "Hello, Alice"
greet("Bob", "Hi");          // "Hi, Bob"

默认参数

typescript
function createUser(name: string, age: int = 18): User {
    return { name, age } as User;
}

// 调用
createUser("Alice");         // age = 18
createUser("Bob", 25);       // age = 25

可变参数

使用 ... 语法接受任意数量的参数:

typescript
// 可变参数
function sum(...numbers: slice<int>): int {
    let total = zero<int>();
    for (const n of numbers) {
        total += n;
    }
    return total;
}

// 调用
sum(1, 2, 3);           // 6
sum(1, 2, 3, 4, 5);     // 15

// 展开切片
let nums: slice<int> = [1, 2, 3, 4];
sum(...nums);           // 10

注意

可变参数必须是函数的最后一个参数。

多返回值

Targo 支持函数返回多个值,这是处理错误的常用模式。

基本用法

typescript
// 返回多个值
function divmod(a: int, b: int): [int, int] {
    return [a / b, a % b];
}

// 解构接收
let [quotient, remainder] = divmod(10, 3);
console.log(quotient);   // 3
console.log(remainder);  // 1

// 忽略某个返回值
let [result, _] = divmod(20, 4);

错误处理模式

Go 风格的错误处理使用多返回值:

typescript
import { New } from "errors";

function divide(a: float64, b: float64): [float64, error | null] {
    if (b == 0) {
        return [0, New("division by zero")];
    }
    return [a / b, null];
}

// 使用
let [result, err] = divide(10, 2);
if (err != null) {
    console.error("Error:", err);
    return;
}
console.log("Result:", result);

TypeScript 对比

TypeScript 使用 try/catch 处理错误,Targo 使用多返回值。这种模式更显式,强制你处理错误。

泛型函数

泛型让函数可以处理多种类型。

基本泛型

typescript
// 泛型函数
function identity<T>(x: T): T {
    return x;
}

// 类型推断
let s = identity("hello");   // string
let n = identity(42);        // int

// 显式类型参数
let b = identity<bool>(true);

多个类型参数

typescript
function pair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

let p = pair("Alice", 30);  // [string, int]

泛型约束

使用 extends 限制类型参数:

typescript
// 接口约束
interface Stringer {
    toString(): string;
}

function stringify<T extends Stringer>(x: T): string {
    return x.toString();
}

// 使用 Go 内置约束
import { Ordered } from "cmp";

function max<T extends Ordered>(a: T, b: T): T {
    return a > b ? a : b;
}

// 使用
max(5, 10);           // 10
max(3.14, 2.71);      // 3.14
max("apple", "banana"); // "banana"

闭包

闭包是可以捕获外部变量的函数。

基本闭包

typescript
function makeCounter(): () => int {
    let count = zero<int>();
    
    return (): int => {
        count++;
        return count;
    };
}

let counter = makeCounter();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3

闭包捕获

闭包捕获外部变量的引用:

typescript
function createAdder(x: int): (y: int) => int {
    return (y: int): int => x + y;
}

let add5 = createAdder(5);
let add10 = createAdder(10);

console.log(add5(3));   // 8
console.log(add10(3));  // 13

高阶函数

接受或返回函数的函数:

typescript
// 接受函数作为参数
function filter<T>(items: slice<T>, predicate: (item: T) => bool): slice<T> {
    let result = slice.make<T>(0, items.len());
    
    for (const item of items) {
        if (predicate(item)) {
            result = slice.append(result, item);
        }
    }
    
    return result;
}

// 使用
let numbers: slice<int> = [1, 2, 3, 4, 5, 6];
let evens = filter(numbers, x => x % 2 == 0);  // [2, 4, 6]

循环中的闭包

Targo 的闭包行为与 TypeScript 的 let 一致:

typescript
function createFunctions(): slice<() => int> {
    let funcs = slice.make<() => int>(0, 3);
    
    for (let i = 0; i < 3; i++) {
        funcs = slice.append(funcs, () => i);
    }
    
    return funcs;
}

let fns = createFunctions();
console.log(fns[0]());  // 0
console.log(fns[1]());  // 1
console.log(fns[2]());  // 2

TypeScript 对比

Targo 的循环变量捕获行为与 TypeScript 的 let 相同,每次迭代创建独立副本。

延迟执行(defer)

defer 用于延迟执行代码,常用于资源清理。

基本用法

typescript
import { Open } from "os";

function processFile(path: string): error | null {
    let [file, err] = Open(path);
    if (err != null) {
        return err;
    }
    
    // 函数返回时自动关闭文件
    defer(() => file.Close());
    
    // 处理文件...
    return null;
}

多个 defer

多个 defer 按 LIFO(后进先出)顺序执行:

typescript
function example(): void {
    defer(() => console.log("first"));   // 最后执行
    defer(() => console.log("second"));  // 中间执行
    defer(() => console.log("third"));   // 最先执行
    
    console.log("main");
}

// 输出:
// main
// third
// second
// first

多语句 defer

typescript
import { Now, Since } from "time";

function trace(name: string): void {
    let start = Now();
    
    defer(() => {
        let elapsed = Since(start);
        console.log(`${name} took ${elapsed}`);
    });
    
    // 执行操作...
}

常见用例

typescript
// 资源清理
function withResource(): void {
    let resource = acquire();
    defer(() => resource.release());
    
    // 使用资源...
}

// 互斥锁
import { Mutex } from "sync";

function criticalSection(mu: Mutex): void {
    mu.Lock();
    defer(() => mu.Unlock());
    
    // 临界区代码...
}

// 错误恢复
function safeOperation(): void {
    defer(() => {
        let err = recover();
        if (err != null) {
            console.log("Recovered from:", err);
        }
    });
    
    // 可能 panic 的代码...
}

方法

方法是附加到类型上的函数。

定义方法

typescript
class Point {
    x: float64;
    y: float64;
    
    // 方法可以修改 this
    scale(factor: float64): void {
        this.x *= factor;
        this.y *= factor;
    }
    
    // 方法可以返回值
    distance(): float64 {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }
}

// 使用
let p = new Point();
p.x = 3;
p.y = 4;
console.log(p.distance());  // 5
p.scale(2);
console.log(p.x, p.y);      // 6, 8

方法链

方法可以返回 this 实现链式调用:

typescript
class Builder {
    #value: string;
    
    append(s: string): Builder {
        this.#value += s;
        return this;
    }
    
    build(): string {
        return this.#value;
    }
}

// 链式调用
let result = new Builder()
    .append("Hello")
    .append(" ")
    .append("World")
    .build();  // "Hello World"

函数类型

函数可以作为类型使用。

类型别名

typescript
// 定义函数类型
type Handler = (req: Request, res: Response) => void;
type Comparator = (a: int, b: int) => int;
type Callback = (err: error | null, data: string) => void;

// 使用函数类型
function processRequest(handler: Handler): void {
    // ...
}

// 函数作为参数
function sort(items: slice<int>, compare: Comparator): void {
    // ...
}

函数作为值

typescript
// 函数赋值给变量
let operation: (a: int, b: int) => int;

operation = (a, b) => a + b;
console.log(operation(5, 3));  // 8

operation = (a, b) => a * b;
console.log(operation(5, 3));  // 15

// 函数存储在 map 中
let operations = map.make<string, (a: int, b: int) => int>();
operations.set("add", (a, b) => a + b);
operations.set("multiply", (a, b) => a * b);

let add = operations.get("add");
console.log(add(5, 3));  // 8

实用模式

工厂函数

typescript
class User {
    name: string;
    age: int;
    email: string;
}

// 工厂函数代替构造函数
function NewUser(name: string, age: int, email: string): User {
    return { name, age, email } as User;
}

// 使用
let user = NewUser("Alice", 30, "alice@example.com");

选项模式

typescript
class ServerOptions {
    host?: string;
    port?: int;
    timeout?: int;
}

function createServer(opts: ServerOptions): Server {
    let host = opts.host ?? "localhost";
    let port = opts.port ?? 8080;
    let timeout = opts.timeout ?? 30;
    
    // 创建服务器...
}

// 使用
createServer({ port: 3000 });
createServer({ host: "0.0.0.0", port: 8080, timeout: 60 });

函数组合

typescript
// 组合多个函数
function compose<T>(
    ...fns: slice<(x: T) => T>
): (x: T) => T {
    return (x: T): T => {
        let result = x;
        for (const fn of fns) {
            result = fn(result);
        }
        return result;
    };
}

// 使用
let addOne = (x: int): int => x + 1;
let double = (x: int): int => x * 2;
let square = (x: int): int => x * x;

let transform = compose(addOne, double, square);
console.log(transform(3));  // ((3 + 1) * 2)² = 64

记忆化

typescript
function memoize<T, R>(fn: (arg: T) => R): (arg: T) => R {
    let cache = map.make<T, R>();
    
    return (arg: T): R => {
        let [cached, exists] = cache.getOK(arg);
        if (exists) {
            return cached;
        }
        
        let result = fn(arg);
        cache.set(arg, result);
        return result;
    };
}

// 使用
let fibonacci = memoize((n: int): int => {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(40));  // 快速计算

常见陷阱

忘记初始化变量

typescript
// ❌ 错误
function calculate(): int {
    let result: int;  // 编译错误:未初始化
    // ...
    return result;
}

// ✅ 正确
function calculate(): int {
    let result = zero<int>();
    // ...
    return result;
}

闭包捕获循环变量

typescript
// ✅ 正确:Targo 自动处理
let funcs = slice.make<() => int>(0, 3);
for (let i = 0; i < 3; i++) {
    funcs = slice.append(funcs, () => i);  // 每次迭代捕获独立的 i
}

defer 的执行时机

typescript
// defer 在函数返回时执行,不是作用域结束时
function example(): void {
    for (let i = 0; i < 3; i++) {
        defer(() => console.log(i));  // 所有 defer 在函数结束时执行
    }
    console.log("done");
}
// 输出: done, 2, 1, 0

下一步

参考资源