Kor*_*nel 6 rust variable-length-array borrow-checker
我知道Rust不支持可变长度数组,但这让我想知道如何替换它们,因为:
我正在转换的C代码通过调用每行的回调来处理图像,传递一小部分指针:
float *tmp[img->channels]; // Small, up to 4 elements
for(int y = 0; y < height; y++) {
for(int ch = 0; ch < img->channels; ch++) {
tmp[ch] = &img->channel[ch]->pixels[width * y];
}
callback(tmp, img->channels);
}
Run Code Online (Sandbox Code Playgroud)
我的Rust尝试(例如在围栏):
for y in 0..height {
let tmp = &img.channel.iter().map(|channel| {
&mut channel.pixels.as_ref().unwrap()[width * y .. width * (y+1)]
}).collect();
callback(tmp);
}
Run Code Online (Sandbox Code Playgroud)
但它被拒绝了:
[&mut [f32]]无法通过迭代器在类型元素上构建类型集合&mut [f32]
可悲的是,这听起来就像我试图做的那样!
我尝试使用固定大小的数组,但Rust不支持泛型,所以我不能从迭代器填充它,我不能在类似C的循环中填充它们,因为引用了循环不会比它活得更久.
core::iter::FromIterator<&mut [f32]>该类型没有实现特征[&mut [f32]; 4]
从固定大小的数组中获取内存片段的另一种方法也失败了:
let mut row_tmp: [&mut [f32]; 4] = unsafe{mem::zeroed()};
for y in 0..height {
row_tmp[0..channels].iter_mut().zip(img.chan.iter_mut()).map(|(t, chan)| {
*t = &mut chan.img.as_ref().unwrap()[(width * y) as usize .. (width * (y+1)) as usize]
});
cb(&row_tmp[0..channels], y, width, image_data);
}
Run Code Online (Sandbox Code Playgroud)
错误:不能
img.chan一次多次借用可变性
arrayvec是一个可以满足您需求的库。(此外,您可能想要iter_mutandas_mut而不是iterand as_ref。)
for y in 0..height {
let tmp: ArrayVec<[_; 4]> = img.channel.iter_mut().map(|channel| {
&mut channel.pixels.as_mut().unwrap()[width * y .. width * (y+1)]
}).collect();
callback(&tmp);
}
Run Code Online (Sandbox Code Playgroud)
它在堆栈上分配固定数量的存储空间(此处为 4 个项目),其行为类似于Vec其大小有界(直至编译时指定的容量)但可变的。
中的大部分复杂性arrayvec是处理为可变数量的项目运行析构函数。但是由于&mut _没有析构函数,您也可以通过固定大小的数组获得一种方法。但是您必须使用unsafe代码并注意不要读取未初始化的项目。(固定大小的数组没有实现FromIterator,这就是Iterator::collect使用。)
(围栏)
let n_channels = img.channel.len();
for y in 0..height {
let tmp: [_; 4] = unsafe { mem::uninitialized() }
for (i, channel) in img.channel.iter_mut().enumerate() {
tmp[i] = &mut channel.pixels.as_mut().unwrap()[width * y .. width * (y+1)];
}
// Careful to only touch initialized items...
callback(&tmp[..n_channels]);
}
Run Code Online (Sandbox Code Playgroud)
编辑:不安全代码可以替换为:
let mut tmp: [&mut [_]; 4] = [&mut [], &mut [], &mut [], &mut []];
Run Code Online (Sandbox Code Playgroud)
较短的[&mut []; 4]初始化语法在此处不适用,因为&mut [_]它不可隐式复制。类型注释是必要的,所以你不会得到[&mut [_; 0]; 4].