# — 运算符重载编程指南
> 玄铁通过**魔术方法**(Magic Methods)支持运算符重载,使自定义类型可使用 `+`、`==` 等原生运算符。本文档覆盖完整 API、实现细节与实战示例。
---
## 快速开始
```xuantie
型 向量 {
设 x
设 y
函 造(ax, ay) { 此.x = ax ; 此.y = ay }
函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
}
设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2 // 自动调用 v1._加_(v2)
示("v3=(" & v3.x.转字() & "," & v3.y.转字() & ")")
// 输出: v3=(4,6)
```
---
## 魔术方法对照表
| 运算符 | 魔术方法 | 参数 | 返回值 | 等效调用 |
|--------|---------|------|--------|---------|
| `+` | `_加_` | `(other)` | 新实例 | `a._加_(b)` |
| `-` | `_减_` | `(other)` | 新实例 | `a._减_(b)` |
| `*` | `_乘_` | `(other)` | 新实例 | `a._乘_(b)` |
| `/` | `_除_` | `(other)` | 新实例 | `a._除_(b)` |
| `%` | `_模_` | `(other)` | 新实例 | `a._模_(b)` |
| `==` | `_等_` | `(other)` | `布尔`(真/假) | `a._等_(b)` |
| `!=` | `_等_` | `(other)` | `布尔`(取反) | `非 a._等_(b)` |
### `==` 与 `!=` 的限定规则
`==` 和 `!=` 仅在**至少一个操作数为自定义类型**(变量类型含 `型:` 前缀)时启用重载。否则直接走内建 `xt_eq`(指针/值比较)。这意味着:
- `弱引用 == 字符串` → 内建比较,不触发 `_等_`
- `整型 == 整型` → 内建比较
- `向量 == 向量` → 重载 `_等_`
---
## 算术重载详解
### 单次加法
```xuantie
型 向量 {
设 x, y
函 造(ax, ay) { 此.x = ax ; 此.y = ay }
函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
}
设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2
若 v3.x == 4 且 v3.y == 6 { 示("PASS: 单次加法正确") }
```
### 链式加法
```xuantie
设 total = 造 向量(0, 0)
设 k = 0
当 k < 20 {
total = total + 造 向量(1, 1)
k = k + 1
}
若 total.x == 20 且 total.y == 20 { 示("PASS: 链式加法正确") }
```
### 嵌套表达式
```xuantie
设 a = 造 向量(1, 0)
设 b = 造 向量(0, 1)
设 c = 造 向量(2, 3)
设 result = a + b + c // 等价于 (a + b) + c
若 result.x == 3 且 result.y == 4 { 示("PASS: 嵌套表达式正确") }
```
---
## 比较重载详解
### `==` 重载
```xuantie
型 向量 {
设 x, y
函 造(ax, ay) { 此.x = ax ; 此.y = ay }
函 _等_(other) {
返 此.x == other.x 且 此.y == other.y
}
}
设 v1 = 造 向量(5, 5)
设 v2 = 造 向量(5, 5)
若 v1 == v2 { 示("相等") } 否 { 示("不等") }
```
### `!=` 重载
`!=` 不需要单独定义——编译器自动对 `_等_` 的结果取反:
```xuantie
若 非 (v1 != v2) { 示("v1 和 v2 相等") }
// v1 != v2 → 调用 v1._等_(v2) → 取反 → 实现 != 语义
```
---
## 实现原理
### 编译期分派
编译器在遇到运算符时:
1. 检查操作数类型是否为标量(`raw_i64` / `i1` / `double`)→ 标量直接生成 LLVM 原生指令(如 `add i64`)
2. 非标量类型 → 查找魔术方法(如 `_加_`)→ 通过 `xt_dict_get` 动态分派
3. `==` / `!=` 特殊处理:仅当操作数含自定义类型(`型:` 前缀)时启用重载,否则走 `xt_eq`(内建指针/值比较)
### 运行时流程(以 `v1 + v2` 为例)
```
1. 检查 v1 是否为堆指针(bit 0 == 0)
2. 若是:xt_dict_get(v1, "_加_") 查找魔术方法
3. 找到 → 提取 XTFunction → 调用 func_ptr(v1, v2)
4. 未找到 → 回退到内建 LLVM 运算
```
### `==` 的入口 alloca 提升
`==` 的重载路径使用 `alloca` 作为 PHI 节点的替代方案(在 overload/fallback 两分支存储结果,merge 处加载)。为避免 LLVM 支配性错误,此 `alloca` 被提升到函数入口块。
> 此机制是本会话修复的核心内容——此前 inline alloca 在 `若` 条件块内导致"Instruction does not dominate all uses!"错误。
---
## 完整测试示例
参见项目测试文件:[Test/52_运算符重载链.xt](https://github.com/MARKJY-China/XuanTie-Lang/blob/master/Test/52_%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD%E9%93%BE.xt)
```xuantie
型 向量 {
设 x, y
函 造(ax, ay) { 此.x = ax ; 此.y = ay }
函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
函 _等_(other) { 返 此.x == other.x 且 此.y == other.y }
函 转字() { 返 "向量(" & 此.x.转字() & "," & 此.y.转字() & ")" }
}
设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2
示("v1+v2=" & v3.转字()) // 向量(4,6)
设 v4 = 造 向量(5, 5)
设 v5 = 造 向量(5, 5)
若 v4 == v5 { 示("v4 等于 v5") } // 由 _等_ 判断
若 v4 != v5 { 示("不等") } 否 { 示("相等") } // _等_ 结果取反
```
---
## 已知限制
- **`==` 重载仅限自定义类型**:弱引用、Result、Socket 等运行时类型不触发 `_等_`,直接走内建 `xt_eq`(指针比较)。如需值语义比较,需手动调用方法。
- **链式 `==` 不推荐**:`a == b == c` 会先计算 `a == b`(返回布尔),再与 `c` 比较。布尔与自定义类型的 `==` 走内建路径。