Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何使用(不安全的)别名?_Rust_Strict Aliasing_Borrow Checker - Fatal编程技术网

Rust 如何使用(不安全的)别名?

Rust 如何使用(不安全的)别名?,rust,strict-aliasing,borrow-checker,Rust,Strict Aliasing,Borrow Checker,Rust有严格的别名规则。但如果“我知道我在做什么”,我能绕过他们吗 我试图将C函数转换为Rust函数,该函数通过读取输入缓冲区和写入目标缓冲区来执行复杂的操作,但它有一个巧妙的优化,允许输入和输出缓冲区相同: foo(src, dst); // result is written to dst foo(buf, buf); // legal in C, does the operation in-place 为了回答这个问题,我们可以这样说: void inplace(char *src,

Rust有严格的别名规则。但如果“我知道我在做什么”,我能绕过他们吗

我试图将C函数转换为Rust函数,该函数通过读取输入缓冲区和写入目标缓冲区来执行复杂的操作,但它有一个巧妙的优化,允许输入和输出缓冲区相同:

foo(src, dst); // result is written to dst
foo(buf, buf); // legal in C, does the operation in-place
为了回答这个问题,我们可以这样说:

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
   }
}
void-in-place(char*src、char*dst、int-len){
对于(int i=0;i
在Rust的安全子集中,我必须有两个几乎复制粘贴的函数版本
fn(&mut)
fn(&mut)


有没有办法欺骗Rust获得对同一缓冲区的可变和不可变引用?

Rust不允许您对可变进行参数化,没有

理论上,您可以编写一些不安全的代码来别名指针,但您必须直接使用原始指针


&mut
意味着指针没有别名,优化器会将其视为别名。使用一个原始指针和一个
&mut
指针仍然会导致问题。

为了使用原始指针,必须使用不安全的代码来实现主功能。原始指针允许您绕过Rust的别名规则。然后,您可以使用两个函数作为此不安全实现的安全外观

不安全的fn foo(src:*常量u8,dst:*mut u8,len:usize){
对于0..len-1中的i{
*dst偏移量(i为isize)=*src偏移量(i为isize+1)*2;
}
}
fn foo_in place(buf:&mut[u8]){
不安全{foo(buf.as_ptr(),buf.as_mut_ptr(),buf.len())}
}
fn foo_独立(src:&[u8],dst:&mut[u8]){
断言!(src.len()==dst.len());
不安全{foo(src.as_ptr(),dst.as_mut_ptr(),src.len())}
}
fn main(){
设src=&[0,1,2,3,4,5];
设dst=&mut[0,0,0,0,0,0];
设buf=&mut[11,22,33,44,55,66];
foo_separate(src、dst);
foo_inplace(buf);
println!(“src:{:?}”,src);
println!(“dst:{:?}”,dst);
println!(“buf:{:?}”,buf);
}

as_ptr()
as_mut_ptr()
len()
是打开的方法。

您可以使用宏在安全代码中实现这一点。它适用于所有具有
len
函数并支持索引的参数。这基本上是duck类型

macro_rules! inplace(
    ($a:ident, $b:ident) => (for i in 0..($a.len()-1) {
        $a[i] = $b[i + 1] * 2;
    })
);

fn main() {
    let mut arr = [1, 2, 3, 4, 5];
    inplace!(arr, arr);
    println!("{:?}", arr);
}
输出

[4,6,8,10,5]


不,你不能在安全的地方这样做。如果您希望,您可以使用不安全的代码来绕过别名限制,但是

但它有一个巧妙的优化,允许输入和输出缓冲区相同

你称之为优化,我称之为悲观

当两个缓冲区保证不相同时,优化器可以对代码进行矢量化。这意味着循环的比较减少了4倍或8倍,大大加快了较大输入的执行速度

但是,在没有别名信息的情况下,它必须悲观地假设输入可能被别名化,因此无法进行此类优化。更糟糕的是,由于不知道它们的别名,它甚至不知道是
&dst[i]=&src[i-1]
还是
&dst[i]=&src[i]
&dst[i]=&src[i+1]
;这意味着预取已完成,等等



但是,在安全防锈中,此信息可用。它确实迫使您编写两个例程(一个用于一个输入,一个用于两个输入),但这两个例程都可以相应地进行优化。

如果它们具有不同的语义,您不打算拥有两个不同的函数吗?@RobertHarvey Semantic是相同的:从第一个指针获取输入,并将输出写入第二个指针。输入和输出缓冲区可以相同,这只是一个重要的优化。您可以使用
*const
*mut
,但这样您就失去了与这些内存相关的所有安全保证。这不是巧合,没有可变别名是Rust的许多保证的核心。因为您已经在创建外观,所以您可以在内部使用您想要的任何东西。因此,我建议在内部使用,将其保存在安全代码中。当存在相同的安全代码版本时,绝不应使用不安全代码。