【问题标题】:How to satisfy trait bounds when making this function generic?使此函数通用时如何满足特征界限?
【发布时间】:2021-01-11 21:26:12
【问题描述】:

我一直在使用 image-rs (0.23.12) 库来实现一些基本的图像分析功能,通过学习 Rust(我来自 Javascript/Python 背景)。我通过 image-rs 为此目的提供的迭代器访问像素数据。这是一个函数的最小示例,它接受对图像子区域 (image::SubImage) 的引用并遍历其中的像素,与每个像素进行比较。

(游乐场link

extern crate image;

use image::{GenericImageView, SubImage, ImageBuffer, Luma};

fn main() {
    let grey_image = ImageBuffer::new(300, 200);

    let subimg = grey_image.view(100, 100, 20, 20);
    
    find_dark_pixels(&subimg);
}

fn find_dark_pixels(img: &SubImage<&ImageBuffer<Luma<u8>, Vec<u8>>>)
{
    static WHITE: Luma<u8> = Luma([255]);
    let mut pixel_iter = img.pixels();
    if pixel_iter.any(|(_, _, pixel)| pixel != WHITE) {
        println!("Found dark pixels!");
    }
}

image::Luma 是一个单色像素。)这个非通用版本的函数编译和运行得很好。但是,它确实要求参数是SubImage,仅此而已。不是很有用 - 它确实需要根据需要对整个图像或一个子集进行操作。允许这样做的 trait 是 GenericImageView,Image 和 SubImage 都实现了它。

我的第一次尝试是将函数签名更改为:

fn find_dark_pixels<I: GenericImageView>(img: &I)

从编译器中引出这个:

binary operation `!=` cannot be applied to type `<I as GenericImageView>::Pixel`
the trait `std::cmp::PartialEq` is not implemented for `<I as GenericImageView>::Pixel` rustc(E0369)

image-rs 中的像素类型确实实现了PartialEq,所以我告诉编译器:

fn find_dark_pixels<I: GenericImageView>(img: &I)
    where <I as GenericImageView>::Pixel: std::cmp::PartialEq
(the rest is unchanged)

然后它抱怨闭包中的“像素”和“白色”的类型不匹配:

mismatched types
expected associated type `<I as GenericImageView>::Pixel`
            found struct `Luma<u8>`
consider constraining the associated type `<I as GenericImageView>::Pixel` to `Luma<u8>`
for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html rustc(E0308)

我遵循(我相信?)编译器的建议并将函数签名更改为:

fn find_dark_pixels<I: GenericImageView>(img: &I)
    where <I as GenericImageView>::Pixel: Luma<u8>
(the rest is unchanged)

编译器计数器:

expected trait, found struct `Luma`
not a trait rustc(E0404)

此时,我尝试以各种方式注释“像素”和“白色”,但我认为自己很难过。你知道,我也知道,Luma 实现了比较所需的一切pixel != WHITE,但我不知道如何说服 rustc。

(如果有帮助,该函数只适用于 Luma&lt;u8&gt;, Vec&lt;u8&gt; 类型的 ImageBuffers 是可以的 - 我只需要使用单色图像。但它确实需要使用任何(不可变的)图像视图。)

【问题讨论】:

  • 欢迎来到 Stack Overflow!很难回答您的问题,因为它不包含minimal reproducible example。我们无法分辨代码中存在哪些 crate(及其版本)、类型、特征、字段等。如果您尝试在Rust Playground 上重现您的错误,如果可能的话,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后在edit 您的问题中包含附加信息。您可以使用Rust-specific MRE tips 来减少您在此处发布的原始代码。谢谢!
  • edit 您的问题并粘贴您所遇到的确切和全部错误——这将有助于我们了解问题所在,以便我们提供最佳帮助。有时试图解释错误消息很棘手,实际上错误消息的不同部分很重要。请使用直接运行编译器的消息,而不是 IDE 生成的消息,它可能会尝试为您解释错误。
  • 我相信编译器关于“约束关联类型”的建议希望你这样做fn find_dark_pixels&lt;I: GenericImageView&lt;Pixel = Luma&lt;u8&gt;&gt;&gt;(img: &amp;I)
  • 解决了,谢谢!

标签: generics rust traits


【解决方案1】:

编译器关于“将关联类型&lt;T as Trait&gt;::Associated约束为Concrete”的建议意味着您需要直接在特征绑定中为关联类型请求具体类型。这是通过Trait&lt;Associated = Concrete&gt; 语法完成的——例如要将I 约束为生成字符串的迭代器,您可以编写I: Iterator&lt;Item = String&gt;。在 find_dark_pixels 的情况下,您将请求 Pixel 关联类型为 Luma&lt;u8&gt;,如下所示:

fn find_dark_pixels<I: GenericImageView<Pixel = Luma<u8>>>(img: &I) {

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-23
    • 2022-11-27
    • 1970-01-01
    • 2019-05-11
    • 2021-01-17
    • 2019-10-11
    • 2019-06-04
    • 2021-02-04
    相关资源
    最近更新 更多