在Rust中通过枚举类型实现延迟加载

在我的用例中,我有一大堆Layer类型的列表,其中包括图像数据和有关图像的一些元数据:

extern crate image;

type Img = image::ImageBuffer<image::Rgba<u8>,Vec<u8>>;

#[derive(Debug,Clone)]
struct Layer {
    // some metadata fields
    lazy_image: Img,}

到目前为止一切顺利。但是,我在实际处理图像数据之前执行了一些层选,所以我想以一种懒惰的方式执行图像加载,以避免必须加载我实际上不需要的所有图像。

这是我的第一次尝试:

extern crate image;

type Img = image::ImageBuffer<image::Rgba<u8>,Clone)]
enum LazyImage {
    Path(String),Image(Img)
}

#[derive(Debug,Clone)]
struct Layer {
    // some metadata fields
    lazy_image: LazyImage,}

impl Layer {
    fn get_image(&mut self) -> Img {
        match self.lazy_image {
            LazyImage::Image(img) => img,LazyImage::Path(path) => {
                let img = image::open(path).expect("Could not open image").to_rgba();
                self.lazy_image = LazyImage::Image(img);
                img
            }
        }
    }
}

您可以猜测,由于get_image中我的match语句存在所有权问题,因此无法使用。编译器建议我借用self.lazy_image,基本上是这样做的:

impl Layer {
    fn get_image(&mut self) -> Img {
        match &self.lazy_image {
            LazyImage::Image(img) => img,LazyImage::Path(path) => {
                let img = image::open(path).expect("Could not open image").to_rgba();
                self.lazy_image = LazyImage::Image(img);
                img
            }
        }
    }
}

现在,我遇到类型问题:第一个分支(如果图像已经加载)返回引用&Img,而不是实际的Img。好的,没问题,让我们参考一下。唯一要注意的是,由于我正在对这些图像进行处理,因此它们必须是可变的:

impl Layer {
    fn get_image(&mut self) -> &mut Img {
        match &self.lazy_image {
            LazyImage::Image(img) => img,LazyImage::Path(path) => {
                let img = image::open(path).expect("Could not open image").to_rgba();
                self.lazy_image = LazyImage::Image(img);
                &mut img
            }
        }
    }
}

现在它们是相同的类型,但是可变性不同:在第一个分支中(如果图像已经加载),我得到一个不可变的引用。我已经尝试了一些尝试,但未能成功完成我想要的操作。

您可能会说,我对Rust还是有些陌生,并且还有些不足。而且,我实际上不确定要实现自己的目标想要做什么。

任何帮助,无论是告诉我如何满足编译器要求,还是只是告诉我我要解决所有错误,都将不胜感激。

waitwat 回答:在Rust中通过枚举类型实现延迟加载

我建议直接在get()类型上实现LazyImage方法,因为感觉加载图像是该类型的内部问题。

由于您很可能不想将图像移出数据结构,因此应返回&mut Img。该引用又需要指向存储在Image枚举变量中的值。枚举变体字段只能通过解构来提取,因此我们需要在加载图像后再次进行解构。

一种可能的解决方案是使用两个if let语句进行销毁:

impl LazyImage {
    fn get(&mut self) -> &mut Img {
        if let LazyImage::Path(path) = self {
            let img = image::open(path).expect("Could not open image").to_rgba();
            *self = LazyImage::Image(img);
        }
        if let LazyImage::Image(img) = self {
            img
        } else {
            unreachable!()
        }
    }
}

在第一个if let之后,保证枚举为Image。第二种解构也可以使用match表达式来完成。编译器将坚持我们包括else的情况,因为编译器无法轻易地看到另一个分支是不可达的。

请注意,我们使用match ergonomics来避免代码中出现一些杂音。

本文链接:https://www.f2er.com/2790471.html

大家都在问