处理f64或Complex64返回类型。泛型?要么?

时间:2017-05-28 15:03:54

标签: rust generic-programming either

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

(缩减示例)函数采用一些配置结构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)
            }
        }
    }
}

我现在希望添加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.))
    }
}

此功能是我程序中的早期切入点,填充ndarray::Array3;目前我正在使用ndarray::Array3<f64>类型的多个变量进行操作 - 所以我需要概括整个程序,而不仅仅是这个函数。

如何根据config的输入扩展此程序以使用这两种类型?此结构来自解析磁盘上的配置文件,并且将匹配多个{{1值。

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

  1. 使用与generalisation over many types类似的内容,并返回PotentialType::Complex*表示真实,Left表示复数;然后使用其他逻辑在其他函数中单独处理值。
  2. 使用泛型类型。这不是我以前做过太多的事情而且Get-Member似乎是我当前代码库的一大堆复杂变更。有没有办法降低复杂性?
  3. 如果您有任何其他建议,我很乐意听到它们!

1 个答案:

答案 0 :(得分:4)

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

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

我做了一个非常similar change in the Euclid library。这是一年多以前,从那时起,Rust和这个库中发生了很多变化,但快速浏览一下这个提交仍然可以让你知道必要的更改量。

这是相同(重命名)实现的current state

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...

}

其中一些特征(TrigOneZero)实际上是defined inside the crate,因为它们不在标准库中。