"polymorphic" return 的 Rust 特性的简单组织

Simple organization of Rust traits for "polymorphic" return

我有一个名为 Frame 的基本结构,可用于一系列计算:。

pub struct Frame<T> {
    grid_val: Vec<T>,
    grid_space: Vec<[T; 2]>,
    calculated_result: Option<Vec<T>>
}

Frame可以用来描述最基本的计算,但有时会出现更复杂的问题,我需要添加更多的几何信息。所以我为每个几何体使用了合成:

pub struct Sphere<T> {
    grid: Frame<T>,
    radius: T
}

pub struct Hyperbola<T> {
    top_grid: Frame<T>,
    bottom_grid: Frame<T>,
    internal_angle: T
}

现在我有一个用于 SphereAlgorithm 的工作实现:

pub trait Algorithm<T> {
    fn calculate_something(&self) -> Result<Sphere<T>, Error>
}

impl Algorithm<T> for Hyperbola {
    // do things with top_grid, bottom_grid, and internal_angle
}

impl Algorithm<T> for Sphere {
    // do things with grid and radius
}

这填写 calculated_result 和 return 一个新的 Sphere。它以这种方式实现是因为 Algorithm 需要使用额外的几何信息来计算 calculated_result — 从语义上讲,它是几何上的实现更有意义,其结果恰好与一个相关联或更多 Frames.

我想为 Hyperbola 实现相同的 Algorithm。其实已经很接近了,trait一样是有道理的,但是要return一个Sphere<T>.

就没意义了

我知道我可以添加另一个特征,例如 GeometricObject 并添加另一层构图,但这似乎过分了。我想我也许可以使用 Box,但这看起来很笨拙。

我还想过 calculate_something return 手动插入一个 Vec<T> 到任何正在使用的结构中,但是 return 的人体工程学是一样的调用该方法的结构类型被破坏(这在 public impl/trait 中是一种浪费)。

我怎样才能在不让它一直保持特征的情况下组织起来?

您似乎想要一个关联类型:

pub trait Algorithm<T> {
    type Output;

    fn calculate_something(&self) -> Result<Self::Output, Error>;
}

impl<T> Algorithm<T> for Sphere<T> {
    type Output = Sphere<T>;

    fn calculate_something(&self) -> Result<Self::Output, Error> {
        unimplemented!()
    }
}

impl<T> Algorithm<T> for Hyperbola<T> {
    type Output = Hyperbola<T>;

    fn calculate_something(&self) -> Result<Self::Output, Error> {
        unimplemented!()
    }
}

关联类型are described in detail in The Rust Programming Language。我 强烈建议 通读整本书以熟悉 Rust 必须提供的功能类型。

另一种解决方案是在特征上定义另一个通用类型:

pub trait Algorithm<T, Out = Self> {
    fn calculate_something(&self) -> Result<Out, Error>;
}

impl<T> Algorithm<T> for Sphere<T> {
    fn calculate_something(&self) -> Result<Sphere<T>, Error> {
        unimplemented!()
    }
}

impl<T> Algorithm<T> for Hyperbola<T> {
    fn calculate_something(&self) -> Result<Hyperbola<T>, Error> {
        unimplemented!()
    }
}

然后你需要决定