使此函数通用时如何满足特征界限?

How to satisfy trait bounds when making this function generic?

我一直在使用 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 而不是其他任何东西。不是很有用 - 它确实需要根据需要对整个图像或图像的子集进行操作。允许这样做的特征是 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)

然后它抱怨闭包中的 'pixel' 和 'WHITE' 的类型不匹配:

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)

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

(如果有帮助,该函数只适用于 Luma<u8>, Vec<u8> 类型的 ImageBuffers 就可以了 - 我只需要处理单色图像。但它确实需要处理任何 (不可变的)图像视图。)

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

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