Skip to content

常见模式对比

本指南展示 TypeScript 和 Targo 中常见编程模式的对比,帮助你快速适应 Targo 的编程风格。

异步操作

单个异步操作

typescript
// TypeScript
async function fetchUser(id: number): Promise<User> {
    const response = await fetch(`/api/users/${id}`);
    return response.json();
}

const user = await fetchUser(123);

// Targo
import { Get } from "net/http";
import { Unmarshal } from "encoding/json";
import { ReadAll } from "io";

function fetchUser(id: int): chan<User> {
    let ch = chan.make<User>();
    
    go(() => {
        let [resp, err] = Get(`/api/users/${id}`);
        if (err != null) {
            ch.close();
            return;
        }
        
        let [body, err2] = ReadAll(resp.Body);
        resp.Body.Close();
        
        if (err2 != null) {
            ch.close();
            return;
        }
        
        let user = zero<User>();
        Unmarshal(body, ref(user));
        ch.send(user);
        ch.close();
    });
    
    return ch;
}

let userCh = fetchUser(123);
let user = userCh.receive();

并行请求

typescript
// TypeScript - Promise.all
const [user, posts, comments] = await Promise.all([
    fetchUser(id),
    fetchPosts(id),
    fetchComments(id)
]);

// Targo - 并发 goroutine
let userCh = chan.make<User>();
let postsCh = chan.make<slice<Post>>();
let commentsCh = chan.make<slice<Comment>>();

go(() => { userCh.send(fetchUser(id)); });
go(() => { postsCh.send(fetchPosts(id)); });
go(() => { commentsCh.send(fetchComments(id)); });

let user = userCh.receive();
let posts = postsCh.receive();
let comments = commentsCh.receive();

超时处理

typescript
// TypeScript
const timeout = (ms: number) => 
    new Promise((_, reject) => 
        setTimeout(() => reject(new Error('Timeout')), ms)
    );

try {
    const result = await Promise.race([
        fetchData(),
        timeout(5000)
    ]);
} catch (error) {
    console.error('Request timed out');
}

// Targo
import { After } from "time";

let dataCh = fetchData();
let timeout = After(5 * time.Second);

switch (chan.$select) {
    case dataCh.$recv:
        let result = dataCh.$value;
        console.log("Got data:", result);
        break;
    
    case timeout.$recv:
        console.error("Request timed out");
        break;
}

数组操作

Map(转换)

typescript
// TypeScript
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(x => x * 2);

// Targo - 使用 Array
let numbers: Array<int> = [1, 2, 3, 4, 5];
let doubled = numbers.map(x => x * 2);

// Targo - 使用 slice(手动循环)
let numbers2: slice<int> = [1, 2, 3, 4, 5];
let doubled2 = slice.make<int>(numbers2.len());
for (let i = 0; i < numbers2.len(); i++) {
    doubled2[i] = numbers2[i] * 2;
}

Filter(过滤)

typescript
// TypeScript
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(x => x % 2 === 0);

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

// Targo - 使用 slice(手动循环)
let numbers2: slice<int> = [1, 2, 3, 4, 5];
let evens2 = slice.make<int>(0, numbers2.len());
for (const num of numbers2) {
    if (num % 2 == 0) {
        evens2 = slice.append(evens2, num);
    }
}

Reduce(归约)

typescript
// TypeScript
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, x) => acc + x, 0);

// Targo - 使用 Array
let numbers: Array<int> = [1, 2, 3, 4, 5];
let sum = numbers.reduce((acc, x) => acc + x, 0);

// Targo - 使用 slice(手动循环)
let numbers2: slice<int> = [1, 2, 3, 4, 5];
let sum2: int = 0;
for (const num of numbers2) {
    sum2 += num;
}

Find(查找)

typescript
// TypeScript
const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
];
const user = users.find(u => u.id === 2);

// Targo - 使用 Array
let users: Array<User> = [
    { id: 1, name: "Alice" } as User,
    { id: 2, name: "Bob" } as User
];
let user = users.find(u => u.id == 2);

// Targo - 使用 slice(手动循环)
let users2: slice<User> = [
    { id: 1, name: "Alice" } as User,
    { id: 2, name: "Bob" } as User
];
let user2: User | null = null;
for (const u of users2) {
    if (u.id == 2) {
        user2 = u;
        break;
    }
}

对象操作

对象字面量

typescript
// TypeScript
const user = {
    id: 1,
    name: 'Alice',
    email: 'alice@example.com'
};

// Targo
class User {
    id: int;
    name: string;
    email: string;
}

let user = {
    id: 1,
    name: "Alice",
    email: "alice@example.com"
} as User;

对象解构

typescript
// TypeScript
const { name, email } = user;

// Targo
let name = user.name;
let email = user.email;

对象合并

typescript
// TypeScript
const defaults = { host: 'localhost', port: 3000 };
const config = { ...defaults, port: 8080 };

// Targo
class Config {
    host: string;
    port: int;
}

let defaults = { host: "localhost", port: 3000 } as Config;
let config = { host: defaults.host, port: 8080 } as Config;

遍历对象属性

typescript
// TypeScript
const obj = { a: 1, b: 2, c: 3 };
for (const [key, value] of Object.entries(obj)) {
    console.log(key, value);
}

// Targo - 使用 map
let m = map.of<string, int>(
    ["a", 1],
    ["b", 2],
    ["c", 3]
);

for (const [key, value] of m) {
    console.log(key, value);
}

类继承 vs 组合

简单继承

typescript
// TypeScript
class Animal {
    name: string;
    
    constructor(name: string) {
        this.name = name;
    }
    
    speak(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    bark(): void {
        console.log('Woof!');
    }
}

const dog = new Dog('Buddy');
dog.speak();  // "Buddy makes a sound"
dog.bark();   // "Woof!"

// Targo - 使用组合
class Animal {
    name: string;
    
    speak(): void {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Embedding({ animal: {} as Animal }) {
    bark(): void {
        console.log("Woof!");
    }
}

function NewDog(name: string): Dog {
    let dog = new Dog();
    dog.animal.name = name;
    return dog;
}

let dog = NewDog("Buddy");
dog.animal.speak();  // "Buddy makes a sound"
dog.bark();          // "Woof!"

多重继承

typescript
// TypeScript - 使用 mixin
class Flyable {
    fly(): void {
        console.log('Flying');
    }
}

class Swimmable {
    swim(): void {
        console.log('Swimming');
    }
}

class Duck extends Flyable {
    // 只能继承一个类
}

// Targo - 使用多重组合
class Flyable {
    fly(): void {
        console.log("Flying");
    }
}

class Swimmable {
    swim(): void {
        console.log("Swimming");
    }
}

class Duck extends Embedding({
    flyable: {} as Flyable,
    swimmable: {} as Swimmable
}) {
    quack(): void {
        console.log("Quack!");
    }
}

let duck = new Duck();
duck.flyable.fly();      // "Flying"
duck.swimmable.swim();   // "Swimming"
duck.quack();            // "Quack!"

错误处理

基本错误处理

typescript
// TypeScript
function divide(a: number, b: number): number {
    if (b === 0) {
        throw new Error('Division by zero');
    }
    return a / b;
}

try {
    const result = divide(10, 0);
} catch (error) {
    console.error('Error:', error.message);
}

// Targo
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, 0);
if (err != null) {
    console.error("Error:", err);
}

错误传播

typescript
// TypeScript
async function processFile(path: string): Promise<string> {
    try {
        const data = await readFile(path);
        const parsed = await parseData(data);
        return parsed;
    } catch (error) {
        throw new Error(`Failed to process file: ${error.message}`);
    }
}

// Targo
import { Errorf } from "fmt";

function processFile(path: string): [string, error | null] {
    let [data, err] = readFile(path);
    if (err != null) {
        return ["", Errorf("failed to read file: %w", err)];
    }
    
    let [parsed, err2] = parseData(data);
    if (err2 != null) {
        return ["", Errorf("failed to parse data: %w", err2)];
    }
    
    return [parsed, null];
}

自定义错误

typescript
// TypeScript
class ValidationError extends Error {
    constructor(message: string) {
        super(message);
        this.name = 'ValidationError';
    }
}

throw new ValidationError('Invalid input');

// Targo
class ValidationError {
    message: string;
    
    Error(): string {
        return this.message;
    }
}

function NewValidationError(message: string): error {
    return { message } as ValidationError;
}

// 使用
return [zero<Result>(), NewValidationError("invalid input")];

模块系统

导出和导入

typescript
// TypeScript
// math.ts
export function add(a: number, b: number): number {
    return a + b;
}

export const PI = 3.14159;

// main.ts
import { add, PI } from './math';

// Targo
// math.ts
export function add(a: int, b: int): int {
    return a + b;
}

export const PI: float64 = 3.14159;

// main.ts
import { add, PI } from "./math";

默认导出

typescript
// TypeScript
// user.ts
export default class User {
    name: string;
}

// main.ts
import User from './user';

// Targo - 没有默认导出,使用命名导出
// user.ts
export class User {
    name: string;
}

// main.ts
import { User } from "./user";

导入 Go 包

typescript
// Targo
import { Println, Printf, Sprintf } from "fmt";
import { ReadFile, WriteFile } from "os";
import { Get, Post } from "net/http";
import { Sleep } from "time";

// 使用别名
import { Println as print } from "fmt";
print("Hello");

工具函数

Debounce

typescript
// TypeScript
function debounce<T extends (...args: any[]) => any>(
    func: T,
    wait: number
): (...args: Parameters<T>) => void {
    let timeout: NodeJS.Timeout;
    return (...args) => {
        clearTimeout(timeout);
        timeout = setTimeout(() => func(...args), wait);
    };
}

// Targo
import { AfterFunc, Stop } from "time";

function debounce(fn: () => void, wait: time.Duration): () => void {
    let timer: Timer | null = null;
    
    return () => {
        if (timer != null) {
            Stop(timer);
        }
        timer = AfterFunc(wait, fn);
    };
}

Throttle

typescript
// TypeScript
function throttle<T extends (...args: any[]) => any>(
    func: T,
    limit: number
): (...args: Parameters<T>) => void {
    let inThrottle: boolean;
    return (...args) => {
        if (!inThrottle) {
            func(...args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

// Targo
import { NewTicker } from "time";

function throttle(fn: () => void, interval: time.Duration): chan<bool> {
    let ticker = NewTicker(interval);
    let stopCh = chan.make<bool>();
    
    go(() => {
        for {
            switch (chan.$select) {
                case ticker.C.$recv:
                    fn();
                    break;
                
                case stopCh.$recv:
                    ticker.Stop();
                    return;
            }
        }
    });
    
    return stopCh;
}

Retry

typescript
// TypeScript
async function retry<T>(
    fn: () => Promise<T>,
    maxAttempts: number
): Promise<T> {
    for (let i = 0; i < maxAttempts; i++) {
        try {
            return await fn();
        } catch (error) {
            if (i === maxAttempts - 1) throw error;
            await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        }
    }
    throw new Error('Max attempts reached');
}

// Targo
import { Sleep } from "time";

function retry<T>(
    fn: () => [T, error | null],
    maxAttempts: int
): [T, error | null] {
    for (let i = 0; i < maxAttempts; i++) {
        let [result, err] = fn();
        if (err == null) {
            return [result, null];
        }
        
        if (i < maxAttempts - 1) {
            Sleep(time.Second * (i + 1));
        }
    }
    
    return [zero<T>(), New("max attempts reached")];
}

数据结构

Stack(栈)

typescript
// TypeScript
class Stack<T> {
    private items: T[] = [];
    
    push(item: T): void {
        this.items.push(item);
    }
    
    pop(): T | undefined {
        return this.items.pop();
    }
    
    peek(): T | undefined {
        return this.items[this.items.length - 1];
    }
    
    isEmpty(): boolean {
        return this.items.length === 0;
    }
}

// Targo
class Stack<T> {
    #items: slice<T>;
    
    push(item: T): void {
        this.#items = slice.append(this.#items, item);
    }
    
    pop(): T | null {
        if (this.#items.len() == 0) {
            return null;
        }
        let item = this.#items[this.#items.len() - 1];
        this.#items = this.#items.slice(0, this.#items.len() - 1);
        return item;
    }
    
    peek(): T | null {
        if (this.#items.len() == 0) {
            return null;
        }
        return this.#items[this.#items.len() - 1];
    }
    
    isEmpty(): bool {
        return this.#items.len() == 0;
    }
}

Queue(队列)

typescript
// TypeScript
class Queue<T> {
    private items: T[] = [];
    
    enqueue(item: T): void {
        this.items.push(item);
    }
    
    dequeue(): T | undefined {
        return this.items.shift();
    }
    
    isEmpty(): boolean {
        return this.items.length === 0;
    }
}

// Targo
class Queue<T> {
    #items: slice<T>;
    
    enqueue(item: T): void {
        this.#items = slice.append(this.#items, item);
    }
    
    dequeue(): T | null {
        if (this.#items.len() == 0) {
            return null;
        }
        let item = this.#items[0];
        this.#items = this.#items.slice(1);
        return item;
    }
    
    isEmpty(): bool {
        return this.#items.len() == 0;
    }
}

性能优化

预分配容量

typescript
// TypeScript
const items: number[] = [];
for (let i = 0; i < 1000; i++) {
    items.push(i);
}

// Targo - 预分配容量
let items = slice.make<int>(0, 1000);  // 容量 1000
for (let i = 0; i < 1000; i++) {
    items = slice.append(items, i);  // 不会触发重新分配
}

避免不必要的分配

typescript
// TypeScript
function processItems(items: number[]): number[] {
    return items.map(x => x * 2);  // 创建新数组
}

// Targo - 原地修改
function processItems(items: slice<int>): void {
    for (let i = 0; i < items.len(); i++) {
        items[i] *= 2;  // 原地修改,不分配新内存
    }
}

使用 sync.Pool 复用对象

typescript
// Targo
import { Pool } from "sync";

let bufferPool = new Pool();
bufferPool.New = () => slice.make<byte>(0, 1024);

function processData(data: slice<byte>): void {
    // 从池中获取 buffer
    let buf = bufferPool.Get() as slice<byte>;
    
    // 使用 buffer
    // ...
    
    // 清空并归还到池中
    buf.clear();
    bufferPool.Put(buf);
}

下一步

参考资源