我有一些保存图像的代码。这可能需要很长时间,所以我想通过将输入的字符串化版本保存到某个向量中来“模拟”测试功能。
use image::imageops::FilterType;
use image::DynamicImage;
#[cfg(not(test))]
pub fn save_image_file(img: &DynamicImage, file_output_name: &str, multiplier_string: &str) {
img.save(format!(
"output_images/{}_{}x.png",
file_output_name, multiplier_string
));
}
#[cfg(test)]
pub mod img_file_manager_tests {
pub static mut saved_images: Vec<String> = Vec::new();
}
#[cfg(test)]
pub fn save_image_file(img: &DynamicImage, file_output_name: &str, multiplier_string: &str) {
use img_file_manager_tests::saved_images;
saved_images.push(format!("{}_{}", file_output_name, multiplier_string));
}
然后我有一个调用
save_image_file
的函数:
pub fn foo(
new_sizes: Vec<(f64, f64, String)>,
file_output_name: &str,
mut img: DynamicImage,
) {
for (new_width, new_height, multiplier_string) in new_sizes {
img = resize_image(&img, new_width as u32, new_height as u32, FilterType::Lanczos3);
save_image_file(&img, &file_output_name, &multiplier_string);
}
}
然后是
foo
的测试,检查内容是否已保存到向量中:
#[test]
pub fn walks_and_saves() {
use crate::walker::foo;
use crate::img_file_manager::img_file_manager_tests::saved_images;
let mock_sizes = vec![
(1.0, 1.0, "foo".to_string())
];
let mock_output_file_name = "bar";
foo(mock_sizes.clone(), mock_output_file_name, DynamicImage::new_rgb8(0,0));
for (index, (mock_width, mock_height, mock_multiplier_string)) in mock_sizes.iter().enumerate() {
assert_eq!(format!("{}",mock_width), saved_images[index]);
}
}
当我运行这些测试时,尽管出现编译器错误,“使用可变静态”。
我在这里做错了什么?如果生锈中不允许可变静态,那么我如何在我的测试 fn 和 #[cfg(test)] 实现的函数之间共享这个向量?在 Rust 中有一些特殊的方法吗?
要具有可变静态,请使用包含
Mutex
.的不可变静态
可变静态是
unsafe
因为它们 very 容易以产生未定义行为的方式被滥用,正如 Ralf Jung 最近解释的,当你调用 UB 时......
生成的程序是一个随机的字节序列,只是偶然地形成了一个看似可以工作的程序。这就是导致 UB 的代码乐趣。当你用 UB 执行一个程序时,你不能从发生的事情中推断出任何东西,因为那个行为本身是没有意义的。
博文可变静态具有可怕的超能力!不要使用它们更详细地解释了问题,并且有一个名为Consider deprecation of UB-happy
static mut
.的未决问题