“评估需求的溢出”但这种递归不应该发生 [英] "Overflow evaluating the requirement" but that kind of recursion should not happen at all
问题描述
这是一个很长的例子,因为我无法进一步减少它。 Rust Playground
使用std :: marker :: PhantomData;
使用std :: ops :: {Add,Sub,Mul,Div};
酒馆特质标量
:大小+复制+添加<自我,输出=自我> + Sub< Self,Output = Self> + Mul< Self,Output = Self> + Div< Self,Output = Self>
{}
impl标量为u32 {}
pub struct ScalarVal< T>(T)其中T:标量;
酒吧特质像素:大小{
类型标量类型:标量;
}
#[derive(Debug,Copy,Clone,PartialEq)]
pub结构体灰色< BaseTypeP>
其中BaseTypeP:标量
{
强度:BaseTypeP,
}
impl< BaseTypeP>灰色像素< BaseTypeP>
其中BaseTypeP:标量
{
类型ScalarType = BaseTypeP;
}
impl< BaseTypeP>添加<灰色和LT; BaseTypeP>>对于ScalarVal< BaseTypeP>
其中BaseTypeP:标量
{
类型输出=灰色< BaseTypeP>;
fn add(self,rhs:Gray< BaseTypeP>) - >灰色< BaseTypeP> {
未实现!()
}
}
pub结构图< PixelP>
其中PixelP:Pixel
{
_marker:PhantomData< PixelP>,
}
impl< PixelP>添加<图像< PixelP>>对于ScalarVal<< PixelP作为像素> ::标量类型>
其中PixelP:Pixel,
ScalarVal<<像素P作为像素> ::标量类型> ;:添加< PixelP,输出= PixelP>
{
type Output = Image< PixelP>;
fn add(self,rhs:Image< PixelP>) - >图像< PixelP> {
未实现!()
}
}
fn main(){
let a = Gray ::< u32> {强度:41};
let b = ScalarVal(1)+ a;
}
有人可以解释为什么我得到溢出来评估要求< _ as Pixel> :: ScalarType
在该代码段中?
我很困惑,因为:
- 如果删除了第44行中的
Add
实现,则代码编译正常。但不应该使用该实现=>main()
仅使用灰色
而不是Image
- 递归似乎嵌套在
Image< Image< ...>>
结构,但根本不应该发生! - 如果第46行更改为
ScalarVal<< PixelP作为像素> ::标量类型> ;:添加
code>它编译得很好 - 但为什么?
一些上下文
<这是我想要构建的图像处理库的一部分。这个想法是有不同的像素格式(灰色,RGB,拜耳,...)可以用于图像。因此,对于灰度图像,您有
图像<灰色>
。不同的 Pixel
实现可以实现不同的操作符,因此您可以使用它们进行计算(例如 gray_a = gray_b + gray_c
)。在这些实现中也可以使用标量值来做例如 gray_a = gray_b + ScalarVal(42)
。因为我想让 ScalarVal
成为正确的和左手参数,所以需要两个实现( impl Add< Gray< ...> for ScalarVal< ...>
和 impl Add< ScalarVal< ...>> for grey< ; ...>
)。 好了,现在 Image 类型应该实现所有被使用的
像素
类型。如果可以做 gray_pixel +标量(42)
,那么也应该可以做 gray_image + Scalar(42)
。
希望这种说法有道理。
ScalarVal(1)+ a
基本上解析为< ScalarVal(1)as Add> .add(a)
,它在 ScalarVal
上查找 Add
实现。
无论什么原因,先检查一下:
impl< PixelP>添加<图像< PixelP>>对于ScalarVal<< PixelP作为像素> ::标量类型>
其中PixelP:Pixel,
ScalarVal<<像素P作为像素> ::标量类型> ;:添加< PixelP,输出= PixelP>
PixelP
在这一点上没有实际意义,所以 PixelP:Pixel
无法检查。因此,我们得到:
ScalarVal :ScalarType>:Add< PixelP,Output = PixelP>
让我们来简化它。由于 PixelP
目前未知,因此
impl< T>添加<图像< T>>对于ScalarVal< _>
其中ScalarVal< _>:Add< T,Output = T>
因此 ScalarVal< _&< / code>寻找
添加< T,输出= T>
。这意味着我们应该寻找一个合适的 T
。显然,这意味着查看 ScalarVal
的添加
impl
s 。看看同一个,我们得到
impl< T2>添加<图像< T2>>对于ScalarVal< _>
其中ScalarVal < - >:Add
这意味着如果这个匹配, T == Image< T2>
。
很明显, T3 ==图像< T4>
等。这会导致溢出和普遍的悲伤。 Rust永远不会发现一个 disproof ,所以不能保证它会走错路。
Here is a kind of lengthy example because I was not able to reduce it further. 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;
}
Can someone explain why I am getting overflow evaluating the requirement <_ as Pixel>::ScalarType
in that code snippet?
I am confused because:
- If the
Add
implementation in line 44 is removed the code compiles fine. But that implementation should not be used at all =>main()
only usesGray
and notImage
- The recursion seems to be in nested
Image<Image<...>>
structs but that should not happen at all?! - If line 46 is changed to
ScalarVal<<PixelP as Pixel>::ScalarType>: Add
it compiles fine - But why?
Some context
This is part of an image processing library I want to build. The idea is to have different pixel formats (Gray, RGB, Bayer, ...) which can be used for images. Therefore you have Image<Gray>
for a grayscale image. Different Pixel
implementations can implement different operators, so you can do calculations (e.g. gray_a = gray_b + gray_c
) with them. It is also possible to use scalar values in those implementations to do e.g. gray_a = gray_b + ScalarVal(42)
. Because I want to make it possible to have ScalarVal
as right- and left-hand-argument there need to be two implementations (impl Add<Gray<...>> for ScalarVal<...>
and impl Add<ScalarVal<...>> for Gray<...>
).
Ok and now the Image
type should implement all operators which are supported by the used Pixel
type. If it is possible to do gray_pixel + Scalar(42)
it should also be possible to do gray_image + Scalar(42)
.
Hope this kind of makes sense.
ScalarVal(1) + a
resolves basically to <ScalarVal(1) as Add>.add(a)
, which looks for an Add
implementation on ScalarVal
.
For whatever reason, this one is checked first:
impl<PixelP> Add<Image<PixelP>> for ScalarVal<<PixelP as Pixel>::ScalarType>
where PixelP: Pixel,
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
PixelP
is uninstantiated at this point, so PixelP: Pixel
can't be checked. Thus we get to
ScalarVal<<PixelP as Pixel>::ScalarType>: Add<PixelP, Output = PixelP>
Let's simplify this. Since PixelP
is unknown right now, <PixelP as Pixel>::ScalarType
is unknown. The actual information known by the compiler looks more like
impl<T> Add<Image<T>> for ScalarVal<_>
where ScalarVal<_>: Add<T, Output = T>
So ScalarVal<_>
looks for an Add<T, Output = T>
. This means we should look for an appropriate T
. Obviously this means looking in ScalarVal
's Add
impl
s. Looking at the same one, we get
impl<T2> Add<Image<T2>> for ScalarVal<_>
where ScalarVal<_>: Add<T2, Output = T2>
which means that if this one matches, T == Image<T2>
.
Obviously then T2 == Image<T3>
, T3 == Image<T4>
, etc. This results in an overflow and general sadness. Rust never finds a disproof, so can't ever guarantee it's going down the wrong path.
这篇关于“评估需求的溢出”但这种递归不应该发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!