这是一个冗长的例子,因为我无法进一步减少它.铁锈游乐场
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;
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释我为什么要进入overflow evaluating the requirement <_ as Pixel>::ScalarType该代码段吗?
我很困惑,因为:
Add删除第44行中的实现,则代码编译正常.但是不应该使用该实现=> main()仅使用Gray而不是ImageImage<Image<...>>结构中,但这根本不应该发生?!ScalarVal<<PixelP as Pixel>::ScalarType>: Add编译就好 - 但为什么呢?这是我想要构建的图像处理库的一部分.我们的想法是拥有可用于图像的不同像素格式(灰色,RGB,拜耳......).因此,你有Image<Gray>一个灰度图像.不同的Pixel实现可以实现不同的运算符,因此您可以gray_a = gray_b + gray_c使用它们进行计算(例如).也可以在这些实现中使用标量值来进行例如gray_a = gray_b + ScalarVal(42).因为我希望能够进行ScalarVal右手和左手参数,所以需要有两个实现(impl Add<Gray<...>> for ScalarVal<...>和impl Add<ScalarVal<...>> for Gray<...>).
好的,现在该Image类型应该实现所使用Pixel类型支持的所有运算符.如果有可能,gray_pixel + Scalar(42)也应该可以这样做gray_image + Scalar(42).
希望这种有道理.
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>
Run Code Online (Sandbox Code Playgroud)
PixelP此时未实例化,因此PixelP: Pixel无法检查.因此我们得到了
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
Run Code Online (Sandbox Code Playgroud)
让我们简化一下.既然PixelP现在还不知道,<PixelP as Pixel>::ScalarType还不得而知.编译器已知的实际信息看起来更像
impl<T> Add<Image<T>> for ScalarVal<_>
where ScalarVal<_>: Add<T, Output = T>
Run Code Online (Sandbox Code Playgroud)
所以ScalarVal<_>寻找一个Add<T, Output = T>.这意味着我们应该寻找合适的T.显然,这意味着在寻找ScalarVal的Add impl秒.看着同一个,我们得到了
impl<T2> Add<Image<T2>> for ScalarVal<_>
where ScalarVal<_>: Add<T2, Output = T2>
Run Code Online (Sandbox Code Playgroud)
这意味着如果这个匹配,T == Image<T2>.
显然,然后T2 == Image<T3>,T3 == Image<T4>等这导致溢出和一般的悲伤.Rust永远不会发现防伪,因此无法保证它会走错路.