Files
2026-10-13 15:36:42 +08:00

840 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 06 - 面向对象与运算符重载
Viper 中的 `class` 有两种语义:**数据布局**(结构体/联合体/枚举,见 [05-classes.md](05-classes.md))和**面向对象**。OOP 能力由**类内是否存在方法**自动判定(`StructEntry.IsOOP`);多态用 `virtual`,非多态继承(C++ 风格,无 vtable 开销)用 `novirtual`。
> `@t.Object` 装饰器默认**不需要写、也尽量避免使用**——OOP 由「类内是否有方法」自动判定,写与不写行为一致。这是本文唯一一次提及,新代码请直接省略。
## 类修饰符(`virtual` / `novirtual`)
`virtual` / `novirtual` 是前置软关键字,**类级与方法级都可用**:
```python
virtual class Shape: # 类级:默认该类所有方法都进虚表
def area(self) -> float: ...
novirtual def helper(self) -> int: ... # 只有 helper 被排除出虚表
novirtual class Node: # 类级:默认该类所有方法都非虚
def plain(self) -> int: ...
virtual def hooked(self) -> int: ... # 只有 hooked 进虚表
```
- `virtual class` / `novirtual class`:**类级**修饰符——默认该类**所有方法**都采用这个级别;
- `virtual def` / `novirtual def`:**方法级**修饰符——只改变**单个方法**、覆盖类级默认,只能直接写在类体内;
- 例:`novirtual` 类里某个方法想进虚表,写 `novirtual class C:` + `virtual def m(self)`;反之 `virtual` 类里把某方法排除出虚表,写 `virtual class C:` + `novirtual def m(self)`;
- 非法形态(修饰符位置错误、`virtual virtual` 等)编译期 fail-fast。
## 面向对象(OOP)
类内定义成员方法即拥有面向对象支持(成员方法、运算符重载、属性装饰器等);编译器根据「结构体内是否有函数定义」自动判定 OOP 行为。
### 基本定义
```python
class ViperKernel:
BootInfo: bootinfo*
VGA: vga._VGAScreenDriver*
VGA_drv: vga._VGAScreenDriver
def __init__(self):
self.BootInfo = BootInfo
serial.init()
serial.puts("ViperOS VKernel Test\n")
```
避免在 `__init__` 中使用 `return`,虽然不会报错,但是你永远无法获得 `return` 的结果,如果需要提前结束代码流,`return` 也不失为一种办法。
### 成员方法
```python
class Sheet:
id: int
x: int
y: int
w: int
h: int
def __init__(self, x: int, y: int, w: int, h: int):
self.x = x
self.y = y
self.w = w
self.h = h
def MoveTo(self, nx: int, ny: int):
self.x = nx
self.y = ny
def Resize(self, nw: int, nh: int):
self.w = nw
self.h = nh
```
### 方法调用
```python
sheet: Sheet = Sheet(0, 0, 640, 480)
sheet.MoveTo(100, 100)
sheet.Resize(800, 600)
```
### 属性装饰器
支持 Python 的 `@property` 和 `@xxx.setter` 装饰器:
> `@xxx.setter` 和自定义装饰器正在试验阶段,尽可能不要使用
```python
class MyObj:
_value: int
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, v: int):
self._value = v
```
### 静态方法
```python
@staticmethod
def _yield():
pass
```
### 对象指针与解引用
对象类实例通常通过指针操作:
```python
obj_ptr: MyClass* = &MyClass()
obj: MyClass = *obj_ptr
```
### 成员访问
通过 `self` 访问成员变量和方法:
```python
def method(self) -> void:
self.x = 10
y: int = self.y
self.DoSomething()
```
### 内嵌对象
对象类可以包含其他对象实例(非指针):
```python
class Sheet:
_surf_obj: gfx.Surface
_renderer_obj: gfx.Renderer
surf: gfx.Surface*
renderer: gfx.Renderer*
def __init__(self, fb: uint32*, zb: float*, w: int, h: int):
self._surf_obj = gfx.Surface(fb, zb, w, h)
self.surf = &self._surf_obj
self._renderer_obj = gfx.Renderer(self.surf)
self.renderer = &self._renderer_obj
```
### `__before_init__` 方法
仅当类内含方法或继承虚方法时才生成 `__before_init__` 方法(纯数据 `class` 不生成)。它在 `__init__` 之前**自动填充成员默认值**,并对 `virtual` 类初始化 vtable:
```llvm
define void @"<SHA1>.ClassName.__before_init__"(%"<SHA1>.ClassName"* %self) {
entry:
; 对 virtual 类:存储 vtable 指针到 slot 0
; 遍历所有成员:若有默认值则 store 默认值,否则 store 零值
ret void
}
```
**职责**:
- 填充类定义中声明的成员默认值(如 `x: int = 0` 中的 `0`)
- 对无默认值的成员填充类型零值
- 对 `virtual` 类额外初始化 vtable 指针
**调用时机**(由编译器在构造时自动插入):
1. 不存在 `__new__` 时:在 `alloca` 分配之后调用一次,随后进入 `__init__`
2. 存在 `__new__` 时:在 `__new__` 之后对**最终存储指针**调用一次,随后进入 `__init__`
**关于 `__new__`**:
- `__new__` 返回 `self` 时使用默认的 `alloca` 存储
- `__new__` 的签名可与 `__init__` 不同
- `__new__` 与 `virtual` 兼容
- `__new__` 本身不入虚表
**就地构造**:用户也可手动调用 `__before_init__` 实现就地构造(placement new 语义),典型用法见 `mpool.alloc_buf`:
```python
buf: Buf* = pool.alloc(Buf.__sizeof__())
buf.__before_init__() # 填充默认值
buf.__init__(args) # 用户初始化逻辑
```
跨模块导入类时,导入侧也会声明 `__before_init__`,保证跨模块构造行为一致。
## `novirtual` 非多态继承
`novirtual` 启用 C++ 风格的非多态继承(对应 `struct A : B {}` 无 virtual)。与 `virtual` 的区别:
| 特性 | `novirtual` | `virtual` |
|------|---------------|--------------|
| vtable 指针 | ❌ 无 | ✅ 自动插入 slot 0 |
| 虚派发 | ❌ 无 | ✅ 支持 |
| 方法继承 | ✅ 调用点解析直调父类 | ✅ 通过 vtable |
| 字段展平 | ✅ 父类字段前置嵌入 | ✅ 父类字段前置嵌入(vtable 之后) |
| 运行时开销 | 零 | 每次虚调用一次间接跳转 |
### 基本定义
```python
novirtual class LinkedNode:
next: LinkedNode*
prev: LinkedNode*
def append(self, node: LinkedNode*): ...
novirtual class GNode(LinkedNode): # 非多态继承
value: int
```
子类 `GNode` 的结构体布局为 `{next, prev, value}`(父类字段前置,无 vtable 指针)。
### 方法继承机制
子类调用父类方法时,实际机制为**调用点解析**:编译器沿 MRO(方法解析顺序)定位到**定义该方法**的父类,按字节偏移调整 `this` 指针后 `bitcast`,在调用点**直接调用**父类实现(无 wrapper 生成、无尾调用)。
> 这里的 MRO 为「深度优先 + 声明顺序 + 去重」(含自身),**不是** Python 的 C3 线性化;详见 [14-multiple-inheritance.md](14-multiple-inheritance.md)。
### 跨模块继承
跨模块父类(如 `linkedlist.LinkedNode`)的 `novirtual` 标记会在导入时被检测并记录,子类继承时同样跳过 vtable 插入。
### 向下转型
父类指针→子类指针需显式转型(生成 bitcast IR):
```python
root: Node = Node() # Node 继承 LinkedNode
child: LinkedNode* = root.child
# child 是 LinkedNode*,需要转回 Node*:
node: Node* = (Node*)(child)
```
隐式转型仅向上(子→父)。
## `virtual` 虚函数表与多态
> **规划**:将引入 `T1 & T2`(TypeIntersection)表达 object(尤其是带 vtable 的 object)的交集类型,作为多态对象组合的静态类型手段(详见 02-type-system.md 类型组合规划演进,尚未实现)。
> 尽可能避免使用 `self[0]` 来获取结构体成员,其不稳定,也不要手动操作虚表。
用 `virtual`(类级)启用虚函数表支持。启用后,结构体第一个成员自动插入 `i8*` 类型的 vtable 指针。类内需有方法(OOP 行为由「结构体内是否有函数」自动判定)。
### 基本定义
```python
virtual class Base:
def __init__(self):
pass
def method(self) -> int:
return 0
```
在 LLVM IR 中,`virtual` 类的结构体类型自动插入 vtable 指针:
```llvm
%"<SHA1>.Base" = type { i8*, i32 }
```
同时,编译器会生成全局 vtable 变量。vtable 实为 `internal constant struct{ n x i8* }`——即含 n 个 `i8*` 函数指针成员的结构体常量(成员为带 `bitcast` 的初始化文本),变量名为 `<sha1>.Class.vtable`,并非 `[1 x i8*] zeroinitializer`:
```llvm
@"<sha1>.Base.vtable" = internal constant { i8* } {
i8* bitcast (i32 (%"<sha1>.Base"*)* @"<sha1>.Base.method" to i8*)
}
```
### 继承与多态
虚表可以帮你使用继承语法实现多态:
```python
virtual class Base:
def __init__(self):
pass
def method(self) -> int:
return 0
virtual class M1(Base):
def method(self) -> int:
return 1
```
当 M1 被初始化时,VTable 会自动修改,这点和 C++ 相同,尽可能避免直接操作 VTable。
继承时,子类会自动继承父类的成员变量和方法。子类重写父类方法时,vtable 中对应位置的函数指针被子类方法替换,实现多态。
### VTable 运行时修改
如果需要临时构造一个额外的 `Base` 结构体,还可以使用:
```python
virtual class Base:
def __init__(self):
pass
def method(self) -> int:
return 0
def __method1(self) -> int:
return 1
export def main() -> int:
b: Base = Base()
b.method = __method1
```
启用 `VTable` 的表中,允许直接修改内部函数为函数指针,在底层,此操作将修改 `VTable` 来达成目的。编译器会检测当前 vtable 是否与类 vtable 相同,如果相同则创建 vtable 的副本(memcpy),避免修改影响所有实例。
### 虚方法调度机制
虚方法调用的核心流程:
1. 从对象指针 GEP 获取第 0 个 slot(vtable 指针)
2. 加载 vtable 指针
3. bitcast 为 `[N x i8*]*` 类型
4. GEP 获取方法索引处的函数指针
5. 加载函数指针
6. bitcast 为正确的函数指针类型
7. 间接调用
### 方法级虚表开关
类级 `virtual` / `novirtual` 决定**该类所有方法的默认级别**;要单独改变**某一个方法**,就在该方法上加相反的方法级修饰符:
- `novirtual` 类中单独标注 `virtual def` 的方法进入虚表;
- `virtual` 类中单独标注 `novirtual def` 的方法被排除在虚表之外。
```python
novirtual class Node: # 默认:所有方法都非虚
def plain(self) -> int: ... # 跟随类级 → 非虚
virtual def hooked(self) -> int: ... # 仅 hooked 进虚表
virtual class Shape: # 默认:所有方法都进虚表
def area(self) -> float: ... # 跟随类级 → 虚
novirtual def helper(self) -> int: ... # 仅 helper 排除出虚表
```
以上行为由 `func_vtable_test` 实证。
### super()
`super().method(...)` 形态被编译为**静态父类方法调用**(仅该形态被支持),不经过 vtable 动态派发:
```python
virtual class Base:
def method(self) -> void:
pass
virtual class Derived(Base):
def method(self) -> void:
super().method() # 静态调用父类实现
```
## 继承
### 结构体成员继承
当子类继承父类(父类在 `Gen.class_members` 中存在)时:
- 父类的成员变量被继承到子类(排在子类成员之前)
- 父类的默认值也被继承
- 父类的方法被继承(重命名为 `子类名.方法名`)
```python
class Animal:
name: [32]char
age: int
def __init__(self, age: int):
self.age = age
def Speak(self) -> void:
serial.puts("...\n")
class Dog(Animal):
breed: int
def Speak(self) -> void:
serial.puts("Woof!\n")
```
### 异常类继承
Viper 支持异常类的继承,用于 `try/except` 的异常匹配:
```python
class MyError(Exception):
pass
class SpecificError(MyError):
pass
```
详见 [09-exceptions.md](09-exceptions.md)。
## 运算符重载
对象类支持运算符重载。编译器在遇到运算符时,先尝试**左操作数**的 dunder 方法;左操作数无对应方法时,回退**右操作数的反向 dunder**(`a + b` → 先 `a.__add__(b)`,缺失再 `b.__radd__(a)`)。TPC 与 VPC 两端行为一致。
### 算术运算符重载
| 运算符 | Dunder 方法 | 示例 |
|--------|------------|------|
| `+` | `__add__` | `a + b` → `a.__add__(b)` |
| `-` | `__sub__` | `a - b` → `a.__sub__(b)` |
| `*` | `__mul__` | `a * b` → `a.__mul__(b)` |
| `/` | `__truediv__` | `a / b` → `a.__truediv__(b)` |
| `//` | `__floordiv__` | `a // b` → `a.__floordiv__(b)` |
| `%` | `__mod__` | `a % b` → `a.__mod__(b)` |
| `**` | `__pow__` | `a ** b` → `a.__pow__(b)` |
| `&` | `__and__` | `a & b` → `a.__and__(b)` |
| `\|` | `__or__` | `a \| b` → `a.__or__(b)` |
| `^` | `__xor__` | `a ^ b` → `a.__xor__(b)` |
| `<<` | `__lshift__` | `a << b` → `a.__lshift__(b)` |
| `>>` | `__rshift__` | `a >> b` → `a.__rshift__(b)` |
> 基础类型(整数/浮点)的 `**` 由编译器直接 lower 为 `llvm.pow`:整数结果在指数为非负整数常量时回写为左操作数类型,其余为浮点结果。自定义类型的 `**` 走 `__pow__` 重载。
示例:
```python
class Vec2:
x: float
y: float
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __add__(self, other: Vec2) -> Vec2:
result: Vec2 = Vec2(0.0, 0.0)
result.x = self.x + other.x
result.y = self.y + other.y
return result
def __mul__(self, scalar: float) -> Vec2:
result: Vec2 = Vec2(0.0, 0.0)
result.x = self.x * scalar
result.y = self.y * scalar
return result
```
### 增量赋值运算符重载
增量赋值先调度对象的**增量 dunder**(`+=` → `__iadd__`),该类无增量 dunder 时回退对应普通 dunder(`__add__`);基础类型走原生运算。两端支持:
| 运算符 | 增量 Dunder | 回退 Dunder |
|--------|------------|------------|
| `+=` | `__iadd__` | `__add__` |
| `-=` | `__isub__` | `__sub__` |
| `*=` | `__imul__` | `__mul__` |
| `/=` | `__itruediv__` | `__truediv__` |
| `//=` | `__ifloordiv__` | `__floordiv__` |
| `%=` | `__imod__` | `__mod__` |
| `**=` | `__ipow__` | `__pow__` |
| `&=` | `__iand__` | `__and__` |
| `\|=` | `__ior__` | `__or__` |
| `^=` | `__ixor__` | `__xor__` |
| `<<=` | `__ilshift__` | `__lshift__` |
| `>>=` | `__irshift__` | `__rshift__` |
> 调度范围与 TPC 一致:仅**局部变量**目标调度增量 dunder(全局 / `nonlocal` 目标不调度)。重载返回值须与目标变量类型兼容(VPC 侧不兼容时编译期 fail-fast)。
### 比较运算符重载
`__eq__`/`__ne__`/`__lt__`/`__le__`/`__gt__`/`__ge__` 已自动调度(映射与调用点自动调度,`opovl_test` 覆盖);未定义 `__eq__` 时比较回退为默认身份比较。
| 运算符 | Dunder 方法 | 状态 |
|--------|------------|------|
| `==` | `__eq__` | 已自动调度 |
| `!=` | `__ne__` | 已自动调度 |
| `<` | `__lt__` | 已自动调度 |
| `<=` | `__le__` | 已自动调度 |
| `>` | `__gt__` | 已自动调度 |
| `>=` | `__ge__` | 已自动调度 |
### 反向运算符重载
左操作数无对应普通 dunder 时,自动调度右操作数的反向 dunder(`a + b` → `b.__radd__(a)`)。两端支持:
| Dunder 方法 | 语义 |
|------------|------|
| `__radd__` | 右操作数加法 |
| `__rsub__` | 右操作数减法 |
| `__rmul__` | 右操作数乘法 |
| `__rtruediv__` | 右操作数真除法 |
| `__rfloordiv__` | 右操作数整除 |
| `__rmod__` | 右操作数取模 |
| `__rpow__` | 右操作数幂运算 |
| `__rand__` | 右操作数按位与 |
| `__ror__` | 右操作数按位或 |
| `__rxor__` | 右操作数按位异或 |
| `__rlshift__` | 右操作数左移 |
| `__rrshift__` | 右操作数右移 |
### 一元运算符重载
`__neg__`/`__pos__`/`__invert__` 已自动调度。
| 运算符 | Dunder 方法 | 状态 |
|--------|------------|------|
| `-a` | `__neg__` | 已自动调度 |
| `+a` | `__pos__` | 已自动调度 |
| `~a` | `__invert__` | 已自动调度 |
## 可调用对象 `__call__`
对象类定义了 `__call__` 时,`obj(args)` 自动分发到 `obj.__call__(args)`(两端已调度)。
```python
class Counter:
value: int
def __init__(self):
self.value = 0
def __call__(self) -> int:
self.value += 1
return self.value
c: Counter = Counter()
x: int = c() # x = 1
y: int = c() # y = 2
```
## 下标访问重载
### `__getitem__` — 读取
```python
def __getitem__(self, key: int) -> int:
return self.data[key]
```
### `__setitem__` — 赋值
```python
def __setitem__(self, key: int, value: int):
self.data[key] = value
```
### `__delitem__` — 删除
```python
def __delitem__(self, key: int):
pass
```
## 布尔转换 `__bool__`
对象类定义了 `__bool__` 时,条件位置自动调度(两端已调度):`if`/`elif`/`while` 条件、`and`/`or`/`not` 操作数、三元表达式条件。
```python
class Buffer:
size: int
data: [1024]char
def __bool__(self) -> bool:
return self.size > 0
buf: Buffer = Buffer()
if buf:
serial.puts("buffer is not empty\n")
```
## 长度 `__len__`
```python
class Buffer:
size: int
def __len__(self) -> int:
return self.size
buf: Buffer = Buffer()
n: int = len(buf)
```
## 字符串转换 `__str__`
对象类定义了 `__str__` 时,`str(obj)`、`print(obj)` 与 f-string(`f"{obj}"`,未指定格式说明符)自动调度该方法,取其返回的字符串(`const char*`)输出(两端已调度)。
```python
class Point:
x: int
y: int
def __str__(self) -> const char*:
return "Point"
p: Point = Point(1, 2)
print(p) # 调用 p.__str__() → 输出 "Point"
```
## 绝对值 `__abs__`
对象类定义了 `__abs__` 时,`abs(obj)` 自动调度该方法(两端已调度);基础类型仍走内建/C 库 `abs`(`labs`),见 [11-builtins.md](11-builtins.md)。
```python
class SignedValue:
val: int
def __abs__(self) -> int:
if self.val < 0:
return -self.val
return self.val
sv: SignedValue = SignedValue()
sv.val = -42
a: int = abs(sv) # a = 42
```
## 迭代器协议
Viper 的迭代器协议与 Python 相同。`__next__` 带编译器注入的隐藏 `i1*` 参数 `__stop_iter_flag__`:方法内 `raise StopIteration` 会将该参数置位并返回默认值以结束迭代。
### `__iter__` 和 `__next__`
```python
class IntRange:
start: int
end: int
current: int
def __init__(self, start: int, end: int):
self.start = start
self.end = end
self.current = start
def __iter__(self):
return self
def __next__(self, __stop_iter_flag__) -> int: # 编译器注入的隐藏 i1* 参数
if self.current >= self.end:
raise StopIteration
val: int = self.current
self.current += 1
return val
```
### for 循环使用
```python
r: IntRange = IntRange(0, 10)
for i in r:
print(i)
```
编译器生成的等价逻辑:
```c
IntRange r = IntRange_init(0, 10);
IntRange iter = IntRange___iter__(&r);
while (1) {
i1 __stop_iter_flag__ = 0; /* 编译器注入的隐藏 i1* 参数 */
int i = IntRange___next__(&iter, &__stop_iter_flag__);
if (__stop_iter_flag__ == 1) break;
print_int(i);
}
```
## 上下文管理器
`with` 语句要求对象实现 `__enter__` 和 `__exit__` 方法:
```python
class File:
fd: int
path: const char*
def __init__(self, path: const char*, flags: int):
self.path = path
self.fd = -1
def __enter__(self):
self.fd = fat32.open(self.path, self.flags)
return self
def __exit__(self):
fat32.close(self.fd)
def read(self) -> int:
return fat32.read(self.fd)
```
使用方式:
```python
with File("/test.txt", FA_READ) as f:
data: int = f.read()
```
编译器会自动保证 `__exit__` 在 `with` 块结束时被调用。
## 析构 `__del__` / `__delete__`
`del` 的目标形态决定调度的 dunder(两端一致):
| 语句 | 调度 |
|------|------|
| `del obj` | `obj.__delete__()`(类未定义则静默无操作) |
| `del obj.attr` | property deleter(`@attr.deleter`);无 deleter 时回退属性值对象的 `__del__()` |
| `del obj[key]` | `obj.__delitem__(key)` |
```python
del obj # 调用 obj.__delete__()
del arr[idx] # 调用 arr.__delitem__(idx)
```
## `isinstance`
`isinstance(obj, Cls)` 不是关键字,而是编译器在调用点按函数名识别的内建(返回 `i1`)。
```python
if isinstance(obj, Base):
...
if isinstance(obj, (A, B)): # 元组:任一命中即为真
...
```
语义:
- **`virtual` 类(带 vtable)**:运行时读对象头部 vtable 指针,与「目标类**及其全部已知子类**的 vtable 地址集合」逐一比较,相等即真 ⇒ 正确覆盖多态子类(这也是运行期唯一能拿到实际类的途径);
- **`novirtual` 类 / 未知类(无 vtable)**:回退**编译期静态 MRO 判定**(据 obj 的静态类型)——可能保守判假。
第二参数支持:裸类名 / 跨模块 `mod.Cls`(只取短名)/ 元组 `(A, B)`。**不支持** REnum 变体、`t.CEnum` 等。
限制:已知子类集合上限 64、元组上限 15;Viper 侧类型推断失败即 fail-fast(`TypeError: isinstance() 参数类型推断失败`)。
> 注意:胖节点 AST 的节点分派用的是**虚方法 `kind()`**(返回 `ASTKind`),不是 `isinstance`;文档中提到的 `vtype` 字段目前**不存在**(属迁移规划)。
## FakeDuck(伪鸭子类型)
FakeDuck 让**内建类型 `str`**(LLVM 层就是 `i8*`)也能像对象一样调用方法、读写字段——通过**扩展类**实现,**不是**关键字 / 装饰器 / 基类。
### 启用方式(命名约定 + import)
- 扩展类必须命名为 `_str`(字符串扩展方法)或 `_Type`(通用基类),定义在被 `import` 的模块中;
- 使用者 `import _fakeduck`(提供 `_str` / `_Type`);`with` 自动注入还需 `import _withcontent`。
内置扩展类见 [includes/_fakeduck.vp](../includes/_fakeduck.vp):`_Type.type_id()`;`_str` 提供 `upper` / `lower` / `capitalize` / `swapcase` / `title` / `casefold` / `isupper` / `islower` / `isalpha` / `isdigit` / `isalnum` / `isspace` / `isascii` / `istitle` / `split` 等。
### 扩展方法调用
```python
import _fakeduck
a: str = "Hello"
tid: int = a.type_id() # 解析到扩展类 _Type.type_id
u: str = a.upper() # 解析到扩展类 _str.upper
```
分派是**回退**:先走普通结构体方法,全部落空后才尝试 FakeDuck;接收者注解是 `list[...]` 时**跳过**。方法名在 `_Type` / `_str` 中查找。
### 影子字段与 with 自动注入
编译期为每个**裸 `str`** 变量额外开一个影子结构体 `<变量名>__meta__`,用来存 per-instance 字段(`__data__`、`__mbuddy__`):
```python
a.__mbuddy__ = bd # 语法糖,等价 a.set_mbuddy(bd)
d: str = a.__data__ # 读影子字段
```
`with` 上下文可**自动注入**字段:提供方类用类体注解 `__provides__ = ['字段名']` 声明,消费方扩展类用 `__requires__ = ['字段名']` 声明:
```python
with memhub.MemBuddy(arena, 65536) as bd:
s: str = "WithTest" # __mbuddy__ 自动注入,无需手动赋值
u2: str = s.upper()
```
另有 `__require_must__`:表示该字段必须由某个外层 `with` 提供,否则编译期 fail-fast。
### 限制
- 影子结构体**只对裸 `str` 注解创建**(`bytes` / `char*` 不创建);`_bytes` 扩展类**未实现**。
- `len()` / 下标 `[]` / `for` 迭代等**不走 FakeDuck**,而是 `list[T]` 的 dunder / 内建分派。
- `with` 注入依赖运行时 provider 栈([includes/_withcontent.vp](../includes/_withcontent.vp)),未 import `_withcontent` 时跳过注入。
真实用例:[Test/FakeDuckTest](../Test/FakeDuckTest)。
## Dunder 方法完整参考
### 已实现自动调度的 Dunder 方法
| Dunder 方法 | 触发语法 | 说明 |
|------------|---------|------|
| `__init__` | `ClassName(args)` | 构造函数 |
| `__before_init__` | 自动生成 | 填充成员默认值并初始化 vtable(类内含方法或继承虚方法时才生成),在 `__init__` 之前执行 |
| `__add__` | `a + b` | 加法 |
| `__sub__` | `a - b` | 减法 |
| `__mul__` | `a * b` | 乘法 |
| `__truediv__` | `a / b` | 真除法 |
| `__floordiv__` | `a // b` | 整除 |
| `__mod__` | `a % b` | 取模 |
| `__and__` | `a & b` | 按位与 |
| `__or__` | `a \| b` | 按位或 |
| `__xor__` | `a ^ b` | 按位异或 |
| `__lshift__` | `a << b` | 左移 |
| `__rshift__` | `a >> b` | 右移 |
| `__eq__` | `a == b` | 等于(未定义 `__eq__` 时默认身份比较) |
| `__ne__` | `a != b` | 不等于 |
| `__lt__` | `a < b` | 小于 |
| `__le__` | `a <= b` | 小于等于 |
| `__gt__` | `a > b` | 大于 |
| `__ge__` | `a >= b` | 大于等于 |
| `__neg__` | `-a` | 一元负号 |
| `__pos__` | `+a` | 一元正号 |
| `__invert__` | `~a` | 按位取反 |
| `__getitem__` | `obj[key]` | 下标读取 |
| `__setitem__` | `obj[key] = value` | 下标赋值 |
| `__delitem__` | `del obj[key]` | 下标删除 |
| `__len__` | `len(obj)` | 长度 |
| `__iter__` | `for x in obj:` | 获取迭代器 |
| `__next__` | `for x in obj:` | 取下一个值(隐藏 `i1*` 参数 `__stop_iter_flag__`,`raise StopIteration` 置位后返回默认值结束迭代) |
| `__enter__` | `with obj as x:` | 上下文管理器进入 |
| `__exit__` | `with obj as x:` | 上下文管理器退出 |
### 声明支持但未实现自动调度的 Dunder 方法
| Dunder 方法 | 预期触发语法 | 当前状态 |
|------------|------------|---------|
| `__pow__` | `a ** b` | 期望实现:binop `**` 未调度(基础类型 `**` 编译失败;自定义类型走 `__pow__` 重载亦属期望) |
| `__iadd__` | `a += b` | 期望实现:AugAssign 一律按原生运算符展开(`+=`→`add`、`//=`→`sdiv` …),不调用 `__iadd__`,也无 `__add__` 回退 |
| `__isub__` | `a -= b` | 同上 |
| `__imul__` | `a *= b` | 同上 |
| `__itruediv__` | `a /= b` | 同上 |
| `__ifloordiv__` | `a //= b` | 同上 |
| `__imod__` | `a %= b` | 同上 |
| `__ipow__` | `a **= b` | 同上 |
| `__str__` | `str(obj)` / `print(obj)` | 期望实现:`print` 为类型感知格式化(`str`/`%s`、`int`、`float`、`struct` 输出占位符),不调度 `__str__` |
| `__call__` | `obj(args)` | 期望实现:当前未调度 |
| `__bool__` | `if obj:` | 期望实现:当前未调度 |
| `__abs__` | `abs(obj)` | 期望实现:当前未调度 |
| `__del__` | `del obj` | 期望实现:当前未调度 |
| `__delete__` | `del obj` | 期望实现:当前未调度 |
| `__radd__` | 右操作数加法 | 尚未调度 |
| `__rsub__` | 右操作数减法 | 尚未调度 |
| `__rmul__` | 右操作数乘法 | 尚未调度 |
| `__rtruediv__` | 右操作数真除法 | 尚未调度 |
| `__rfloordiv__` | 右操作数整除 | 尚未调度 |
| `__rmod__` | 右操作数取模 | 尚未调度 |
| `__rpow__` | 右操作数幂运算 | 尚未调度 |