rust - 在 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>, Vec<u8>>;
#[derive(Debug, 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
}
}
}
}
正如您可以猜到的那样,这不起作用,因为我的 match 语句存在所有权问题get_image
。编译器建议我借用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 有点陌生,并且有点不知所措。此外,我实际上并不确定我想做什么来实现我想要的目标。
任何帮助,无论是告诉我如何满足编译器,甚至只是告诉我这一切都错了,将不胜感激。
解决方案
我建议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
案例,因为编译器不能轻易地看到另一个分支是不可访问的。
请注意,我们使用匹配人体工程学来避免代码中的一些噪音。
推荐阅读
- c# - 将 WPF 控件转换为 PDF
- react-native - 从 github 打开 react-native 项目时构建失败
- php - PHP Mysqli 数据库连接池以避免最大用户数
- tmux - 从 tmux 命令行创建新窗格
- security - 如何通过 IP 地址限制对我的 subversion 服务器(即 svnserve)的访问,所以只有我的 IP 可以签出、提交等?
- python - Json数据排序PANDAS,python
- php - PHP 正则表达式字符串和减法部分
- apache-spark - 如何在 ElasticSearch 中创建索引并从流式查询中推送数据?
- javascript - javascript onclicking按钮给不同的div
- windows - 在命令行上创建一个 tar.xz 文件