rust 通用特征的覆盖特征实现

xpszyzbs  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(133)

RUSTDOCS给出了以下毯式实现的示例

impl<T: Display> ToString for T {
    // --snip--
}

我更复杂的特性不允许我编写一个全面的实现。

/// a fixed size 2D array (WxH) that can be indexed by [usize;2]
pub trait Grid<C: Copy + Eq, const W: usize, const H: usize>:
    IndexMut<[usize; 2], Output = Option<C>>
{
}

// allow to transform one grid implementation into another 
// as long as they contain the same elements and have the same size
impl<C, O, I, const W: usize, const H: usize> From<I> for O
where
    O: Default + Grid<C, W, H>,
    I: Grid<C, W, H>,
    C: Copy
{
    fn from(input: O) -> O {
        let mut output = O::default();
        for i in 0..O::W {
            for j in 0..O::H {
                output[[i, j]] = input[[i, j]];
            }
        }
        output
    }
}

错误说

the type parameter `C` is not constrained by the impl trait, self type, or predicates

the const parameter `W` is not constrained by the impl trait, self type, or predicates
expressions using a const parameter must map each value to a distinct output value
proving the result of expressions other than the parameter are unique is not supported

感觉它是通过O: Grid<Player, W, H>约束的,但这似乎不是正确的约束。
围绕const泛型参数的错误是次要的(转移注意力?)。当我用常量替换它们时,围绕C(元素类型)的错误仍然存在。

t98cgbkg

t98cgbkg1#

问题是,对于编译器来说,变量CWH可能有多个值,考虑一下如果I实现Grid<Foo, 1, 2> * 和 * Grid<Foo, 500, 50>会发生什么:您的blanket From实现应该使用哪个Grid实现是不明确的。(对于给定的OIC实际上不能有多个值,但编译器实际上并没有推理出这一点。)
这个问题的解决方案是将trait的 * generic * 改为 associated types(和associated constants),这意味着trait不能为同一个self类型实现多次:

use std::ops::IndexMut;
/// a fixed size 2D array (WxH) that can be indexed by [usize;2]
pub trait Grid: IndexMut<[usize; 2], Output = Option<Self::Component>>
{
    type Component: Copy + Eq;
    const WIDTH: usize;
    const HEIGHT: usize;
}

// allow to transform one grid implementation into another 
// as long as they contain the same elements and have the same size
impl<O, I> From<I> for O
where
    O: Default + Grid,
    O::Component: Copy,
    I: Grid<Component = O::Component, WIDTH = O::WIDTH, HEIGHT = O::HEIGHT>,
{
    fn from(input: O) -> O {
        let mut output = O::default();
        for i in 0..O::W {
            for j in 0..O::H {
                output[[i, j]] = input[[i, j]];
            }
        }
        output
    }
}

但是,由于以下几个原因,这仍然无法编译:

  • 你不能为满足某些trait边界的任意两个类型编写From impl,因为它可能会与满足不同边界的任意两个类型的 * 某个其他crate的 * From impl重叠--而且它总是与标准库中的blanket From<T> for T重叠。

一般来说,只能实现From<TypeYouDefined> for TFrom<T> for TypeYouDefined--而不是完全通用的、笼统的From实现。

  • 实际上,你不能像我的代码所建议的那样,写一个两个traits的关联常量相等的界限--编译器假设它必须是一个类型约束,我不知道是否有解决这个问题的方法。

相关问题