处理 f64 或 Complex64 返回类型。泛型?任何一个?

Geo*_*sic 2 generic-programming either rust

我有一个正常运行的 Rust 程序,使用实双精度数 ( f64) 作为基础类型,并希望扩展系统,以便它也可以处理复杂值 ( num::complex::Complex64)。

一个(简化示例)函数采用一些配置 struct config,并根据该输入在索引处生成一个潜在值idx

fn potential(config: &Config, idx: &Index3) -> Result<f64, Error> {
    let num = &config.grid.size;
    match config.potential {
        PotentialType::NoPotential => Ok(0.0),
        PotentialType::Cube => {
            if (idx.x > num.x / 4 && idx.x <= 3 * num.x / 4) &&
               (idx.y > num.y / 4 && idx.y <= 3 * num.y / 4) &&
               (idx.z > num.z / 4 && idx.z <= 3 * num.z / 4) {
                Ok(-10.0)
            } else {
                Ok(0.0)
            }
        }
        PotentialType::Coulomb => {
            let r = config.grid.dn * (calculate_r2(idx, &config.grid)).sqrt();
            if r < config.grid.dn {
                Ok(-1. / config.grid.dn)
            } else {
                Ok(-1. / r)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在希望添加一个ComplexCoulomb返回Complex64值的匹配:

PotentialType::ComplexCoulomb => {
    let r = config.grid.dn * (calculate_r2(idx, &config.grid)).sqrt();
    if r < config.grid.dn {
        Ok(Complex64::new(-1. / config.grid.dn, 1.))
    } else {
        Ok(Complex64::new(-1. / r, 1.))
    }
}
Run Code Online (Sandbox Code Playgroud)

这个函数是我程序中的一个早期入口点,它填充了一个ndarray::Array3; 目前我正在操作许多具有该类型的变量ndarray::Array3<f64>- 所以我需要概括整个程序,而不仅仅是这个函数。

如何扩展该程序以根据输入使用两种类型config该结构来自解析磁盘上的配置文件,并将匹配许多PotentialType::Complex*值。

我知道有两种可能的选择,但不确定是否符合我的标准。

  1. 使用类似于Either的东西并返回Left实数和Right复数;然后使用额外的逻辑在其他函数中单独处理这些值。
  2. 使用泛型类型。这不是我之前做过太多的事情,并且对许多类型的泛化似乎是对我当前代码库的相当大的复杂更改。有没有办法降低这里的复杂性?

如果您有任何其他建议,我很想听听!

Pet*_*all 5

可能会有很多代码更改,但使用通用参数可能是最灵活的方法,并且不会影响性能。传递 an 的enum性能会降低,部分原因是枚举会更大(较大变体的大小加上用于区分它们的标签),部分原因是必须经常检查枚举变体。

可能会变得麻烦的一件事是限制类型参数的可能很长的特征列表。这可以在级别上完成impl,而不是在每个功能上完成,以节省重复。目前还没有一种方法可以对一组特征进行别名,从而使其更符合人体工程学,但有一个RFC对此批准了。

我在 Euclid 库中进行了非常类似的更改。那是一年多前的事了,从那时起,Rust 和该库都发生了很大的变化,但快速浏览一下该提交仍然应该让您了解必要的更改量。

这是同一(重命名)实现的当前状态:

impl <T, Src, Dst> TypedTransform3D<T, Src, Dst>
where T: Copy + Clone +
         Add<T, Output=T> +
         Sub<T, Output=T> +
         Mul<T, Output=T> +
         Div<T, Output=T> +
         Neg<Output=T> +
         ApproxEq<T> +
         PartialOrd +
         Trig +
         One + Zero {

  // methods of TypedTransform3D defined here...

}
Run Code Online (Sandbox Code Playgroud)

其中一些特征(TrigOneZero)实际上是在 crate 内定义的,因为它们不在标准库中。