[英]Rust implementation of split_at_mut
我一直在阅读 Rust Book,在关于 Unsafe Rust 的部分中,它展示了如何实现split_at_mut
方法的简单版本。 给定的实现是:
use std::slice;
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
但是,我想出了这个:
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
assert!(mid <= len);
let begin = &mut values[..mid] as *mut [i32];
let end = &mut values[mid..] as *mut [i32];
unsafe {
(&mut *begin, &mut *end)
}
}
这会产生(据我所知)相同的结果,但在我看来,它更易于阅读。
那么是什么让给定的解决方案比我的“更好”呢? 我的解决方案是否存在安全(或其他)问题? 给定的解决方案实际上更容易阅读吗? 是关于将此方法扩展到其他切片吗? 是关于编码风格和“良好实践”吗?
期待您的回答
这是我认为的原因(正如另一个答案所写)Miri 拒绝您的代码:
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
在这种情况下,您正在从来自单个&mut
引用values
的指针构造两个非重叠的&mut
引用。
let begin = &mut values[..mid] as *mut [i32];
let end = &mut values[mid..] as *mut [i32];
unsafe {
(&mut *begin, &mut *end)
}
在这种情况下,您正在构建两个临时可变引用,它们都从values
中借用(因此不能同时存在),然后从指针“复活”(不是技术术语)它们。
这是相同代码的一个版本,它扩展了一些临时变量和语法糖:
use std::ops::IndexMut;
let begin = {
let v1 = &mut values;
IndexMut::index_mut(v1, ..mid) as *mut [i32]
};
let end = {
let v2 = &mut values;
IndexMut::index_mut(v2, mid..) as *mut [i32]
};
unsafe { (&mut *begin, &mut *end) }
您的两个指针begin
和end
派生自v1
和v2
,因此它们仅在v1
和v2
存在时才有效,但v1
和v2
相互冲突。
综上所述,我不能确定允许这个程序是否可行,因为毕竟它不会创建任何实际的可变别名。 我绝对没有受过 Miri 检查的 Stacked Borrows model 理论基础的教育。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.