Kor*_*nel 5 strict-aliasing rust borrow-checker
Rust有严格的别名规则.但是,如果"我知道我在做什么",我可以解决它们吗?
我正在尝试转换为Rust一个C函数,它通过从输入缓冲区读取并写入目标缓冲区来执行复杂的操作,但它有一个聪明的优化,允许输入和输出缓冲区相同:
foo(src, dst); // result is written to dst
foo(buf, buf); // legal in C, does the operation in-place
Run Code Online (Sandbox Code Playgroud)
为了这个问题,让我们说它是这样的:
void inplace(char *src, char *dst, int len) {
for(int i=0; i < len-1; i++) {
dst[i] = src[i+1] * 2; // algorithm works even if src == dst
}
}
Run Code Online (Sandbox Code Playgroud)
生锈的安全集我得有功能的两个几乎复制和粘贴的版本fn(&mut)和fn(&, &mut).
有没有办法欺骗Rust以获得对同一缓冲区的可变和不可变引用?
Rust 不允许您对可变性进行参数化,不。
理论上,您可以编写一些给指针别名的不安全代码,但您必须直接使用原始指针。
&mut意味着该指针没有别名,优化器会这样对待它。使用一个原始指针和一个&mut指针仍然会导致问题。
不,你不能在安全的Rust中这样做.如果您愿意,可以使用不安全的代码来解决别名限制......
但它有一个聪明的优化,允许输入和输出缓冲区相同
你称之为优化,我称之为悲观.
当两个缓冲区保证不相同时,优化器可以对代码进行矢量化.这意味着循环的比较少4倍或8倍,大大加快了大输入的执行速度.
然而,在没有别名信息的情况下,它必须悲观地假设输入可能是别名的,因此不能进行这样的优化.更糟的是,不知道怎么样,他们的别名,它甚至不知道是否&dst[i] == &src[i-1]或&dst[i] == &src[i]或&dst[i] == &src[i+1]; 这意味着预取等等......
但是,在安全的Rust中,可以获得此信息.它会强制您编写两个例程(一个用于单个输入,一个用于两个输入),但两者都可以相应地进行优化.
为了使用原始指针,您的 main 函数必须使用不安全代码来实现。原始指针允许您绕过 Rust 的别名规则。然后,您可以使用两个函数作为此不安全实现的安全 fa\xc3\xa7ades。
\n\nunsafe fn foo(src: *const u8, dst: *mut u8, len: usize) {\n for i in 0..len - 1 {\n *dst.offset(i as isize) = *src.offset(i as isize + 1) * 2;\n }\n}\n\nfn foo_inplace(buf: &mut [u8]) {\n unsafe { foo(buf.as_ptr(), buf.as_mut_ptr(), buf.len()) }\n}\n\nfn foo_separate(src: &[u8], dst: &mut [u8]) {\n assert!(src.len() == dst.len());\n unsafe { foo(src.as_ptr(), dst.as_mut_ptr(), src.len()) }\n}\n\nfn main() {\n let src = &[0, 1, 2, 3, 4, 5];\n let dst = &mut [0, 0, 0, 0, 0, 0];\n\n let buf = &mut [11, 22, 33, 44, 55, 66];\n\n foo_separate(src, dst);\n foo_inplace(buf);\n\n println!("src: {:?}", src);\n println!("dst: {:?}", dst);\n println!("buf: {:?}", buf);\n}\nRun Code Online (Sandbox Code Playgroud)\n\nas_ptr()、as_mut_ptr()和是切片len()上的方法。