Appearance
使用 Go 包
本指南介绍如何在 Targo 中使用 Go 标准库和第三方包。
目标读众
- 想要使用 Go 生态系统的开发者
- 需要访问 Go 标准库的开发者
- 想要集成第三方 Go 包的开发者
核心概念
Targo 通过 binder 工具生成 TypeScript 类型声明(.d.ts 文件),使你能够在 Targo 代码中使用 Go 包:
- targo bind - 生成类型声明的命令
- .targo/ - 存放生成的类型声明
- 自动导入 - TypeScript 编译器自动识别类型
targo bind 命令
基本用法
使用 targo bind 命令生成 Go 包的类型声明:
bash
# 绑定单个包
targo bind fmt
# 绑定多个包
targo bind fmt os strings
# 绑定第三方包
targo bind github.com/user/package输出结构
绑定后会在 .targo/ 目录下生成类型声明:
.targo/
├── fmt/
│ └── fmt.d.ts
├── os/
│ └── os.d.ts
└── strings/
└── strings.d.ts常用选项
bash
# 指定输出目录
targo bind fmt --output ./types
# 绑定标准库包
targo bind --stdlib fmt os strings使用 Go 标准库
1. fmt - 格式化输出
bash
# 绑定 fmt 包
targo bind fmttypescript
import { fmt } from "fmt";
// 格式化字符串
let msg = fmt.Sprintf("Hello, %s!", "World");
console.log(msg); // "Hello, World!"
// 打印到标准输出
fmt.Println("Hello, World!");
fmt.Printf("Number: %d\n", 42);
// 格式化错误
let err = fmt.Errorf("failed to open file: %s", filename);2. os - 操作系统接口
bash
# 绑定 os 包
targo bind ostypescript
import { os } from "os";
// 读取文件
let [data, err] = os.ReadFile("config.json");
if (err != null) {
console.log(`Error: ${err.Error()}`);
return;
}
console.log(string(data));
// 写入文件
let content = Slice.from("Hello, World!");
let err2 = os.WriteFile("output.txt", content, 0644);
if (err2 != null) {
console.log(`Error: ${err2.Error()}`);
}
// 环境变量
let home = os.Getenv("HOME");
os.Setenv("MY_VAR", "value");
// 文件操作
let [file, err3] = os.Open("data.txt");
if (err3 != null) {
return;
}
defer(() => file.Close());3. strings - 字符串操作
bash
# 绑定 strings 包
targo bind stringstypescript
import { strings } from "strings";
// 字符串操作
let upper = strings.ToUpper("hello"); // "HELLO"
let lower = strings.ToLower("WORLD"); // "world"
// 分割和连接
let parts = strings.Split("a,b,c", ","); // ["a", "b", "c"]
let joined = strings.Join(parts, "-"); // "a-b-c"
// 查找和替换
let contains = strings.Contains("hello", "ell"); // true
let replaced = strings.Replace("hello", "l", "L", -1); // "heLLo"
// 修剪
let trimmed = strings.TrimSpace(" hello "); // "hello"4. http - HTTP 客户端和服务器
bash
# 绑定 http 包
targo bind net/httpHTTP 客户端:
typescript
import { http } from "net/http";
import { io } from "io";
// GET 请求
let [resp, err] = http.Get("https://api.github.com");
if (err != null) {
console.log(`Error: ${err.Error()}`);
return;
}
defer(() => resp.Body.Close());
// 读取响应
let [body, err2] = io.ReadAll(resp.Body);
if (err2 != null) {
console.log(`Error: ${err2.Error()}`);
return;
}
console.log(`Status: ${resp.StatusCode}`);
console.log(`Body: ${string(body)}`);HTTP 服务器:
typescript
import { http } from "net/http";
import { fmt } from "fmt";
function handler(w: http.ResponseWriter, r: http.Request): void {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]);
}
http.HandleFunc("/", handler);
console.log("Server starting on :8080");
http.ListenAndServe(":8080", null);5. json - JSON 编解码
bash
# 绑定 json 包
targo bind encoding/jsontypescript
import { json } from "encoding/json";
interface User {
ID: int;
Name: string;
Email: string;
}
// 编码(序列化)
let user: User = { ID: 1, Name: "Alice", Email: "alice@example.com" };
let [data, err] = json.Marshal(user);
if (err != null) {
console.log(`Error: ${err.Error()}`);
return;
}
console.log(string(data));
// 解码(反序列化)
let jsonStr = '{"ID":1,"Name":"Alice","Email":"alice@example.com"}';
let user2: User = zero<User>();
let err2 = json.Unmarshal(Slice.from(jsonStr), ref(user2));
if (err2 != null) {
console.log(`Error: ${err2.Error()}`);
return;
}
console.log(user2.Name); // "Alice"6. time - 时间和日期
bash
# 绑定 time 包
targo bind timetypescript
import { time } from "time";
// 当前时间
let now = time.Now();
console.log(now.String());
// 格式化时间
let formatted = now.Format(time.RFC3339);
console.log(formatted); // "2024-01-01T12:00:00Z"
// 解析时间
let [t, err] = time.Parse(time.RFC3339, "2024-01-01T12:00:00Z");
if (err != null) {
console.log(`Error: ${err.Error()}`);
}
// 时间运算
let tomorrow = now.Add(24 * time.Hour);
let duration = tomorrow.Sub(now);
console.log(duration.Hours()); // 24
// 睡眠
time.Sleep(1 * time.Second);
// 定时器
let timer = time.NewTimer(5 * time.Second);
timer.C.receive(); // 等待 5 秒
console.log("5 seconds passed");使用第三方包
1. 安装 Go 包
首先使用 go get 安装 Go 包:
bash
# 安装第三方包
go get github.com/gorilla/mux
go get github.com/lib/pq2. 绑定包
使用 targo bind 生成类型声明:
bash
# 绑定第三方包
targo bind github.com/gorilla/mux3. 使用包
typescript
import { mux } from "github.com/gorilla/mux";
import { http } from "net/http";
// 创建路由器
let r = mux.NewRouter();
// 定义路由
r.HandleFunc("/", (w, req) => {
w.Write(Slice.from("Home Page"));
});
r.HandleFunc("/users/{id}", (w, req) => {
let vars = mux.Vars(req);
let id = vars["id"];
w.Write(Slice.from(`User ID: ${id}`));
});
// 启动服务器
http.ListenAndServe(":8080", r);常用包示例
文件路径操作
bash
targo bind path/filepathtypescript
import { filepath } from "path/filepath";
// 路径操作
let joined = filepath.Join("dir", "subdir", "file.txt");
let dir = filepath.Dir("/path/to/file.txt"); // "/path/to"
let base = filepath.Base("/path/to/file.txt"); // "file.txt"
let ext = filepath.Ext("file.txt"); // ".txt"
// 路径匹配
let [matched, err] = filepath.Match("*.txt", "file.txt");
if (matched) {
console.log("Matched!");
}
// 遍历目录
filepath.Walk("/path/to/dir", (path, info, err) => {
if (err != null) {
return err;
}
console.log(path);
return null;
});正则表达式
bash
targo bind regexptypescript
import { regexp } from "regexp";
// 编译正则表达式
let [re, err] = regexp.Compile(`\d+`);
if (err != null) {
console.log(`Error: ${err.Error()}`);
return;
}
// 匹配
let matched = re.MatchString("abc123"); // true
let found = re.FindString("abc123def"); // "123"
let all = re.FindAllString("a1b2c3", -1); // ["1", "2", "3"]
// 替换
let replaced = re.ReplaceAllString("a1b2c3", "X"); // "aXbXcX"数据库(PostgreSQL)
bash
go get github.com/lib/pq
targo bind database/sql
targo bind github.com/lib/pqtypescript
import { sql } from "database/sql";
import _ from "github.com/lib/pq"; // 导入驱动
// 连接数据库
let [db, err] = sql.Open("postgres", "user=postgres dbname=mydb sslmode=disable");
if (err != null) {
console.log(`Error: ${err.Error()}`);
return;
}
defer(() => db.Close());
// 查询
let [rows, err2] = db.Query("SELECT id, name FROM users WHERE age > $1", 18);
if (err2 != null) {
console.log(`Error: ${err2.Error()}`);
return;
}
defer(() => rows.Close());
// 遍历结果
while (rows.Next()) {
let id: int = 0;
let name: string = "";
let err3 = rows.Scan(ref(id), ref(name));
if (err3 != null) {
console.log(`Error: ${err3.Error()}`);
continue;
}
console.log(`${id}: ${name}`);
}
// 插入
let [result, err4] = db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", "Alice", 25);
if (err4 != null) {
console.log(`Error: ${err4.Error()}`);
}类型映射
Go 类型到 Targo 类型
| Go 类型 | Targo 类型 | 说明 |
|---|---|---|
int, int64 | int, int64 | 整数 |
float64 | float64 | 浮点数 |
string | string | 字符串 |
bool | bool | 布尔值 |
[]T | slice<T> | 切片 |
[N]T | Fixed<T, N> | 数组 |
map[K]V | map<K, V> | 映射 |
chan T | chan<T> | 通道 |
*T | T | 指针(默认引用) |
interface{} | any | 空接口 |
error | error | null | 错误 |
函数签名
Go 函数的多返回值映射为 Targo 的元组:
go
// Go
func ReadFile(name string) ([]byte, error)typescript
// Targo
function ReadFile(name: string): [slice<byte>, error | null]实际示例
REST API 服务器
typescript
import { http } from "net/http";
import { json } from "encoding/json";
import { fmt } from "fmt";
interface User {
ID: int;
Name: string;
Email: string;
}
let users: User[] = [
{ ID: 1, Name: "Alice", Email: "alice@example.com" },
{ ID: 2, Name: "Bob", Email: "bob@example.com" }
];
function getUsersHandler(w: http.ResponseWriter, r: http.Request): void {
w.Header().Set("Content-Type", "application/json");
json.NewEncoder(w).Encode(users);
}
function getUserHandler(w: http.ResponseWriter, r: http.Request): void {
let id = r.URL.Query().Get("id");
if (id == "") {
http.Error(w, "id is required", 400);
return;
}
let userId = parseInt(id);
for (const user of users) {
if (user.ID == userId) {
w.Header().Set("Content-Type", "application/json");
json.NewEncoder(w).Encode(user);
return;
}
}
http.Error(w, "user not found", 404);
}
http.HandleFunc("/users", getUsersHandler);
http.HandleFunc("/user", getUserHandler);
fmt.Println("Server starting on :8080");
http.ListenAndServe(":8080", null);文件处理工具
typescript
import { os } from "os";
import { filepath } from "path/filepath";
import { strings } from "strings";
function processFiles(dir: string, ext: string): error | null {
return filepath.Walk(dir, (path, info, err) => {
if (err != null) {
return err;
}
if (info.IsDir()) {
return null;
}
if (!strings.HasSuffix(path, ext)) {
return null;
}
console.log(`Processing: ${path}`);
let [data, err2] = os.ReadFile(path);
if (err2 != null) {
return err2;
}
// 处理文件内容...
let processed = process(data);
let err3 = os.WriteFile(path, processed, info.Mode());
if (err3 != null) {
return err3;
}
return null;
});
}
// 使用
let err = processFiles("./src", ".txt");
if (err != null) {
console.log(`Error: ${err.Error()}`);
}常见陷阱
1. 忘记绑定包
typescript
// ❌ 错误:未绑定 fmt 包
import { fmt } from "fmt"; // 类型错误
// ✅ 正确:先绑定包
// 在终端运行:targo bind fmt
import { fmt } from "fmt";2. 错误的导入路径
typescript
// ❌ 错误:使用 Go 导入路径
import { http } from "net/http"; // 正确
// ❌ 错误:使用错误的路径
import { http } from "http"; // 错误3. 指针类型混淆
typescript
// Go: func Open(name string) (*File, error)
// Targo: function Open(name: string): [File, error | null]
// ✅ 正确:File 已经是引用类型
let [file, err] = os.Open("file.txt");
// ❌ 错误:不需要额外的指针
let [file, err] = os.Open("file.txt");
let ptr = ref(file); // 不需要最佳实践
按需绑定包
- 只绑定实际使用的包
- 减少类型声明文件大小
使用标准库
- 优先使用 Go 标准库
- 标准库经过充分测试
检查错误
- 始终检查 Go 函数返回的错误
- 使用
error | null类型
使用 defer 清理资源
- 文件、连接等资源需要关闭
- 使用
defer确保清理
阅读 Go 文档
- 参考 Go 官方文档了解包的用法
- 类型声明与 Go API 一致