Appearance
类型系统
Targo 的类型系统基于 Go,但使用 TypeScript 风格的语法。本指南帮助你理解 Targo 的类型系统及其与 TypeScript 的差异。
核心设计原则
- Go 类型为基础 - 所有类型直接映射到 Go 类型
- TypeScript 语法 - 使用熟悉的 TS 语法表达
- 零运行时开销 - 类型在编译时完全消除
- 显式转换 - 值/引用转换必须显式进行
数值类型
TypeScript vs Targo
TypeScript 只有一个 number 类型,而 Targo 需要明确的数值类型:
typescript
let x: number = 42;
let y: number = 3.14;
let z: number = 255;typescript
let x: int = 42;
let y: float64 = 3.14;
let z: uint8 = 255;整数类型
| Targo 类型 | 大小 | 范围 | 说明 |
|---|---|---|---|
int | 平台相关 | 有符号 | 最常用的整数类型 |
int8 | 1 字节 | -128 到 127 | 小范围整数 |
int16 | 2 字节 | -32,768 到 32,767 | |
int32 | 4 字节 | -2³¹ 到 2³¹-1 | |
int64 | 8 字节 | -2⁶³ 到 2⁶³-1 | 大范围整数 |
uint | 平台相关 | 无符号 | 无符号整数 |
uint8 | 1 字节 | 0 到 255 | 字节值 |
uint16 | 2 字节 | 0 到 65,535 | |
uint32 | 4 字节 | 0 到 2³²-1 | |
uint64 | 8 字节 | 0 到 2⁶⁴-1 | |
byte | 1 字节 | 0 到 255 | uint8 的别名 |
rune | 4 字节 | Unicode 码点 | int32 的别名 |
typescript
let count: int = 42;
let age: int8 = 25;
let port: uint16 = 8080;
let char: rune = 'A';浮点类型
| Targo 类型 | 大小 | 精度 |
|---|---|---|
float32 | 4 字节 | 单精度 |
float64 | 8 字节 | 双精度(推荐) |
typescript
let pi: float64 = 3.14159;
let temperature: float32 = 36.5;其他基础类型
typescript
let name: string = "Targo";
let isValid: bool = true;
let huge: bigint = 123456789012345678901234567890n;值语义 vs 引用语义
这是 Targo 最重要的概念之一。
基本规则
| 类型 | 默认语义 | Go 映射 |
|---|---|---|
原始类型 (int, string, etc.) | 值语义 | 直接值 |
class | 引用语义 | 指针 (*T) |
Val<T> | 值语义 | 值类型 |
Ptr<T> | 引用语义 | 指针 |
Class 默认是引用
typescript
class User {
name: string;
age: int;
}
let user1 = new User(); // User 类型,实际是 *User
user1.name = "Alice";
let user2 = user1; // 引用赋值
user2.name = "Bob"; // 修改 user1 和 user2
console.log(user1.name); // "Bob" - 两者指向同一对象go
// 编译为 Go
type User struct {
Name string
Age int
}
user1 := new(User)
user1.Name = "Alice"
user2 := user1
user2.Name = "Bob"
fmt.Println(user1.Name) // "Bob"原始类型是值
typescript
let x: int = 42;
let y = x; // 值复制
y = 100; // 只修改 y
console.log(x); // 42 - x 不受影响显式转换 API
ref() - 取地址
将值转换为引用/指针:
typescript
// 原始类型 → 指针
let n: int = 42;
let np: Ptr<int> = ref(n);
np.value = 100;
// 值类型 → 引用
let userVal: Val<User> = zero<User>();
let userRef: User = ref(userVal);deref() - 解引用
将引用转换为值:
typescript
let user = new User(); // User (引用)
let userVal: Val<User> = deref(user); // Val<User> (值)
userVal.name = "Bob"; // 修改副本,不影响 userzero<T>() - 零值
获取类型的零值(非 null):
typescript
let n = zero<int>(); // 0
let s = zero<string>(); // ""
let b = zero<bool>(); // false
let u = zero<User>(); // Val<User>,所有字段为零值go
// 编译为 Go
var n int
var s string
var b bool
var u UserzeroNil<T>() - 可空零值
获取可空的零值:
typescript
let arr = zeroNil<slice<int>>(); // slice<int> | null
let m = zeroNil<map<string, int>>(); // map<string, int> | null
let u = zeroNil<User>(); // User | nullgo
// 编译为 Go
var arr []int // nil
var m map[string]int // nil
var u *User // nil可空类型
基本语法
typescript
// 可空类型
let user: User | null = null;
let count: int | null = null; // ❌ 错误:原始类型不能直接为 null
// 可选字段(语法糖)
class Config {
host: string;
port?: int; // 等价于 port: int | null
}空安全访问
typescript
let user: User | null = getUser();
// 检查 null
if (user == null) {
console.log("User not found");
return;
}
// 此处 user 自动收窄为非空类型
console.log(user.name);
// 可选链(如果支持)
user?.name;指针类型
原始类型指针
原始类型需要显式指针:
typescript
let np: Ptr<int> = ref(42);
// 读取
let v = np.value; // 42
// 赋值
np.value = 100;
// 可空指针
let maybeInt: Ptr<int> | null = null;
if (maybeInt != null) {
console.log(maybeInt.value);
}Object 指针
Class 默认就是引用,不需要显式 Ptr<T>:
typescript
let user = new User(); // 已经是指针
user.name = "Alice"; // 自动解引用
// 可空引用
let maybeUser: User | null = null;类型转换
数值类型转换
typescript
let f: float64 = 3.14;
let n = f as int; // 截断为整数
let i: int = 42;
let f2 = i as float64; // 转换为浮点数
let small: int8 = 100;
let big = small as int64; // 扩展精度字符串转换
typescript
let s: string = "hello";
let bytes = s as slice<byte>; // 转换为字节切片
let runes = s as slice<rune>; // 转换为 rune 切片
let data: slice<byte> = slice.of(72, 105);
let str = data as string; // 转换为字符串类型别名和新类型
类型别名
typescript
type ID = int64;
type Handler = (req: Request, res: Response) => void;
let userId: ID = 12345;新类型(Defined Type)
创建全新的类型,与底层类型不兼容:
typescript
class UserID extends DefinedType<int64> {}
class Celsius extends DefinedType<float64> {}
// 使用 as 创建实例
const id = 12345 as UserID;
const temp = 36.5 as Celsius;
// 类型安全:不能互相赋值
const id2: UserID = temp; // ❌ 类型错误go
// 编译为 Go
type UserID int64
type Celsius float64
id := UserID(12345)
temp := Celsius(36.5)函数类型
基本函数类型
typescript
type Handler = (req: Request, res: Response) => void;
type Comparator = (a: int, b: int) => int;多返回值
typescript
// 函数签名
function divmod(a: int, b: int): [int, int] {
return [a / b, a % b];
}
// 使用
let [quotient, remainder] = divmod(10, 3);go
// 编译为 Go(零开销)
func divmod(a, b int) (int, int) {
return a / b, a % b
}
quotient, remainder := divmod(10, 3)与 TypeScript 的对比
相同点
- ✅ 类型注解语法 (
: Type) - ✅ 类型推断
- ✅ 联合类型 (
T | U) - ✅ 泛型 (
<T>) - ✅ 类型别名 (
type)
主要差异
| 特性 | TypeScript | Targo |
|---|---|---|
| 数值类型 | number | int, float64, etc. |
| 数组 | Array<T> 或 T[] | slice<T> |
| null vs undefined | 两者都有 | 只有 null |
| Class 语义 | 引用(JS 对象) | 引用(Go 指针) |
| 类型转换 | 隐式 | 显式 |
| 零值 | undefined | 类型特定的零值 |
实用示例
示例 1: 用户管理
typescript
class User {
id: int64;
name: string;
email: string;
age?: int; // 可选字段
}
function createUser(name: string, email: string): User {
let user = new User();
user.id = generateID();
user.name = name;
user.email = email;
// age 默认为 null
return user;
}
function findUser(id: int64): User | null {
// 查找用户...
return zeroNil<User>(); // 未找到
}
// 使用
let user = findUser(123);
if (user != null) {
console.log(`Found: ${user.name}`);
if (user.age != null) {
console.log(`Age: ${user.age}`);
}
}示例 2: 计数器
typescript
class Counter {
value: int;
increment(): void {
this.value++;
}
getValue(): int {
return this.value;
}
}
// 值语义版本
let counterVal: Val<Counter> = zero<Counter>();
counterVal.value = 10;
let copy = counterVal; // 值复制
copy.value = 20;
console.log(counterVal.value); // 10 - 不受影响
// 引用语义版本
let counter = new Counter();
counter.value = 10;
let ref = counter; // 引用赋值
ref.value = 20;
console.log(counter.value); // 20 - 共享状态常见陷阱
陷阱 1: 忘记类型注解
typescript
// ❌ 错误:Targo 需要明确类型
let x = 42; // 类型推断可能不符合预期
// ✅ 正确:明确指定类型
let x: int = 42;陷阱 2: 混淆值和引用
typescript
// ❌ 错误:期望修改原对象
let user = new User();
let userVal = deref(user); // 创建副本
userVal.name = "Bob"; // 只修改副本
// ✅ 正确:使用引用
let user = new User();
let userRef = user; // 引用赋值
userRef.name = "Bob"; // 修改原对象陷阱 3: null 检查
typescript
// ❌ 错误:TypeScript 风格
if (user) { // Targo 要求显式 bool
// ...
}
// ✅ 正确:显式检查
if (user != null) {
// ...
}最佳实践
- 优先使用
int和float64- 除非有特定需求 - 明确值/引用语义 - 理解何时使用
Val<T>和Ptr<T> - 使用
zero<T>()初始化 - 避免 null 检查 - 显式类型转换 - 不要依赖隐式转换
- 检查 null - 始终显式检查可空类型
下一步
- 集合类型 - 学习 slice、map、chan
- 函数与方法 - 函数定义和多返回值
- TypeScript 到 Targo - 完整的差异对比