利用F#类型约束避免Measurement与Constant加法代码冗余
解决Measurement与Constant加法的代码重复问题
核心方案:接口抽象+通用逻辑复用
你可以通过定义通用接口抽象两类的共性,再提取加法核心逻辑为通用函数,彻底避免重复代码,同时轻松支持顺序反转的加法场景。
1. 定义通用接口
先创建一个接口,统一可参与运算类型的核心操作:
// 抽象可参与运算量的共性:获取值(Var类型)和单位 type IMeasurable = abstract member GetValue : unit -> Var abstract member GetUnit : unit -> Unit
2. 修改现有类型实现接口
让Measurement和Constant都实现这个接口,统一对外暴露运算所需的信息:
type Measurement = private { value: Var uncertainty: float unit: Unit } static let getUncertainty v = let gradV: HashMap<Var,float,System.Collections.Generic.IEqualityComparer<Var>> = grad v gradV |> HashMap.keys |> Seq.fold (fun acc x -> acc + (Uncertainties.Item x * gradV[x]) ** 2.) 0. |> sqrt // 实现IMeasurable接口 interface IMeasurable with member this.GetValue() = this.value member this.GetUnit() = this.unit // 提取通用加法逻辑,用#IMeasurable约束接受任意实现接口的类型 static private let add (a: #IMeasurable) (b: #IMeasurable) = if a.GetUnit() <> b.GetUnit() then invalidOp "Cannot add values with different units" let v = a.GetValue() + b.GetValue() { value = v uncertainty = getUncertainty v unit = a.GetUnit() } // 各类加法运算符直接调用通用逻辑 static member (+)(a: Measurement, b: Measurement) = add a b static member (+)(a: Measurement, b: Constant) = add a b static member (+)(a: Constant, b: Measurement) = add a b type Constant = private { value: float; unit: Unit } // 实现IMeasurable:利用已定义的Var+float加法,将float转为Var interface IMeasurable with member this.GetValue() = Var(0., []) + this.value member this.GetUnit() = this.unit
3. 关键细节说明
- 接口的作用:把
Measurement和Constant的核心操作标准化,让通用函数无需关心具体类型,只依赖接口约定。 - 通用加法函数:
add函数只写一次核心逻辑,所有运算符重载都直接调用它,避免重复的单位检查、值计算、不确定性推导代码。 - 反转加法的支持:
Constant + Measurement的运算符直接复用通用逻辑,无需额外编写重复代码。 - 扩展兼容性:后续如果新增其他可运算类型,只需让它实现
IMeasurable接口,就能直接复用现有加法逻辑。
内容的提问来源于stack exchange,提问作者Timeless0007297
相关产品推荐
相关产品推荐

