本文介绍了“评估需求的溢出”但这种递归不应该发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 这是一个很长的例子,因为我无法进一步减少它。 Rust Playground 好了,现在 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 Playgrounduse 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 ImageThe 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 contextThis 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 toScalarVal<<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 likeimpl<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 getimpl<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. 这篇关于“评估需求的溢出”但这种递归不应该发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-17 05:52