Appearance
函数与方法
函数是 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]()); // 2TypeScript 对比
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下一步
参考资源
- Effective Go - Functions - Go 函数最佳实践
- Go by Example - Functions - Go 函数示例