这是一个冗长的例子,因为我无法进一步减少它。 Rust Playground
use std::marker::PhantomData;
use std::ops::{Add, Sub, Mul, Div};
pub trait Scalar
: Sized + Copy + Add<Self, Output = Self> + Sub<Self, Output = Self> + Mul<Self, Output = Self> + Div<Self, Output = Self>
{}
impl Scalar for u32 {}
pub struct ScalarVal<T>(T) where T: Scalar;
pub trait Pixel: Sized {
type ScalarType: Scalar;
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Gray<BaseTypeP>
where BaseTypeP: Scalar
{
intensity: BaseTypeP,
}
impl<BaseTypeP> Pixel for Gray<BaseTypeP>
where BaseTypeP: Scalar
{
type ScalarType = BaseTypeP;
}
impl<BaseTypeP> Add<Gray<BaseTypeP>> for ScalarVal<BaseTypeP>
where BaseTypeP: Scalar
{
type Output = Gray<BaseTypeP>;
fn add(self, rhs: Gray<BaseTypeP>) -> Gray<BaseTypeP> {
unimplemented!()
}
}
pub struct Image<PixelP>
where PixelP: Pixel
{
_marker: PhantomData<PixelP>,
}
impl<PixelP> Add<Image<PixelP>> for ScalarVal<<PixelP as Pixel>::ScalarType>
where PixelP: Pixel,
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
{
type Output = Image<PixelP>;
fn add(self, rhs: Image<PixelP>) -> Image<PixelP> {
unimplemented!()
}
}
fn main() {
let a = Gray::<u32> { intensity: 41 };
let b = ScalarVal(1) + a;
}
有人可以解释我在该代码段中获取overflow evaluating the requirement <_ as Pixel>::ScalarType
的原因吗?
我很困惑因为:
Add
实现被删除,则代码编译正常。但该实现不应该全部使用=&gt; main()
仅使用Gray
而非Image
Image<Image<...>>
结构,但这根本不会发生?!ScalarVal<<PixelP as Pixel>::ScalarType>: Add
,则编译正常 - 但为什么?这是我想要构建的图像处理库的一部分。我们的想法是拥有可用于图像的不同像素格式(灰色,RGB,拜耳......)。因此,对于灰度图像,您有Image<Gray>
。不同的Pixel
实现可以实现不同的运算符,因此您可以使用它们进行计算(例如gray_a = gray_b + gray_c
)。在这些实现中也可以使用标量值来实现例如标量值。 gray_a = gray_b + ScalarVal(42)
。因为我想让ScalarVal
作为right- 和左手参数成为可能,所以需要有两个实现(impl Add<Gray<...>> for ScalarVal<...>
和impl Add<ScalarVal<...>> for Gray<...>
)。
好的,现在Image
类型应该实现所使用的Pixel
类型支持的所有运算符。如果可以gray_pixel + Scalar(42)
,则也可以执行gray_image + Scalar(42)
。
希望这是有道理的。
答案 0 :(得分:6)
ScalarVal(1) + a
基本上解析为<ScalarVal(1) as Add>.add(a)
,它会在Add
上查找ScalarVal
实施。
无论出于何种原因,首先检查这个:
impl<PixelP> Add<Image<PixelP>> for ScalarVal<<PixelP as Pixel>::ScalarType>
where PixelP: Pixel,
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
此时 PixelP
未实例化,因此无法检查PixelP: Pixel
。因此我们进入
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
让我们简化一下。由于PixelP
目前还不知道,<PixelP as Pixel>::ScalarType
未知。编译器已知的实际信息看起来更像
impl<T> Add<Image<T>> for ScalarVal<_>
where ScalarVal<_>: Add<T, Output = T>
因此ScalarVal<_>
会查找Add<T, Output = T>
。这意味着我们应该寻找合适的T
。显然,这意味着要查看ScalarVal
的{{1}} Add
。看着同一个,我们得到
impl
表示如果此匹配,impl<T2> Add<Image<T2>> for ScalarVal<_>
where ScalarVal<_>: Add<T2, Output = T2>
。
显然然后是T == Image<T2>
,T2 == Image<T3>
等。这会导致溢出和普遍的悲伤。 Rust从未找到 disproof ,因此无法保证它会走错路。