“评估需求的溢出”但这种递归不应该发生 [英] "Overflow evaluating the requirement" but that kind of recursion should not happen at all

查看:78
本文介绍了“评估需求的溢出”但这种递归不应该发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个很长的例子,因为我无法进一步减少它。 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 目前未知,因此< PixelP as Pixel> :: ScalarType 未知。编译器已知的实际信息看起来更像是:

  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>



很明显, T2 == Image< T3> 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 uses Gray and not Image
  • 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 impls. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆