文献声明
本文不是 Rust 教程,也不是量化策略教程。
本文是《Rust 量化算子》基础篇的第二篇,目标是定义算子状态(State)的工程语义与责任边界。
所有代码仅用于验证定义是否可落地,而非教学目标。
作者
yuer
EDCA OS 作者
可控 AI 标准提出者
工程仓库:https://github.com/yuer-dsl
联系邮箱:lipxtk@gmail.com
1. 为什么"状态"不能再被当成变量
在第一篇中,我们已经将算子(Operator)定义为:
在明确执行语义下,被调度的一次执行单元。
一旦接受这个定义,一个问题立刻出现:
跨多次执行的信息,应该存放在哪里?
在实践中,常见做法包括:
-
把中间值存在结构体字段中
-
用
static或全局缓存 -
把状态混入输入数据
这些方式都存在同一个问题:
状态的工程语义是隐式的。
隐式状态在以下场景中会失效:
-
重放(replay / backtest)
-
批量与逐条执行切换
-
多算子复用
-
执行失败后的恢复
2. 核心定义:什么是 State
在本文中,状态(State) 被定义为:
跨多次执行存在,
且其生命周期受执行语义约束的数据实体。
这一定义刻意排除了"变量""缓存"等描述。
状态不是:
-
普通 Rust 变量
-
临时缓存
-
输入数据的一部分
状态必须具备:
-
明确的初始化语义
-
明确的更新规则
-
可预测的重置行为
-
与执行顺序相关
3. 状态的责任归属
本文做出一个刻意保守但可共识的选择:
状态属于算子,而不属于执行环境。
理由很简单:
-
状态的含义由算子语义决定
-
执行环境不应理解业务含义
-
状态共享必须是显式行为
这并不意味着状态一定"存放在算子内部",
而是责任边界在算子一侧。
4. 最小 State 模型(v0.1)
4.1 State trait
pub trait OperatorState { fn reset(&mut self); }
说明:
-
reset是最小生命周期接口 -
不引入序列化、不引入时间
-
仅定义"可重置性"
4.2 StatefulOperator 扩展
pub trait StatefulOperator<Input, Output>: Operator<Input, Output> { type State: OperatorState; fn state(&mut self) -> &mut Self::State; }
说明:
-
状态通过显式接口暴露
-
不允许隐式共享
-
不讨论并发访问
5. 一个最小有状态示例
下面示例并不实现完整指标,仅用于说明状态存在的工程意义。
pub struct CountState { count: usize, } impl OperatorState for CountState { fn reset(&mut self) { self.count = 0; } } pub struct Counter { state: CountState, } impl Operator<&[f64], usize> for Counter { type Error = (); fn execute(&mut self, input: &[f64]) -> Result<usize, Self::Error> { self.state.count += input.len(); Ok(self.state.count) } }
该示例说明:
-
状态跨执行累积
-
状态语义独立于输入
-
执行顺序影响输出
6. 不变量与失败边界
本文明确以下不变量:
-
状态必须可重置
-
状态更新必须只发生在执行期间
-
状态不得依赖隐式全局信息
刻意不支持:
-
隐式状态共享
-
非确定性更新
-
执行外状态突变