为变量创建别名

Bra*_*rey 1 rust borrow-checker

我在 Rust 中有以下代码(它不会编译,但说明了我所追求的内容)。出于可读性目的,我想用两个不同的名称引用同一字符串,以便传递给函数的变量名称与其真正含义相匹配。如果我克隆,这个问题可以“解决”,date_created但随后我会不必要地复制数据。

let date_created: String = utc_now_str();
let paste_state_date = date_created;

// ...

some_function( date_created, paste_state_date );
Run Code Online (Sandbox Code Playgroud)

是否有一种有效的惯用方法来为同一变量创建这个“第二名”?

7st*_*tud 7

我以为我理解这一点,但以下内容不起作用,因为构造对原始内容的引用借用了原始内容,因此似乎我不能在函数调用期间同时使用两者。我错过了一些非常简单的事情吗?

let str1 = ...; 
let str2 = &str1;
my_func(str1, *str2);
Run Code Online (Sandbox Code Playgroud)

您是否熟悉 Rust 中的赋值与 C++ 中的赋值有何不同?这是一个简单的例子:

 let x = "hello".to_string();
 let y = x;
Run Code Online (Sandbox Code Playgroud)

在 Rust 中执行这些语句后,您期望 x 和 y 的值是什么?答案:x没有值,y有“hello”.to_string()返回的值。这在 Rust 中被称为“移动”——换句话说,赋值将值从一个变量移动到另一个变量。

在 C++ 中,如果你写:

string x = "hello";
string y = x;
Run Code Online (Sandbox Code Playgroud)

然后 C++ 会将“hello”复制到 y 中,这将在内存中留下两个字符串。在 Rust 中使用赋值时,您必须意识到这种差异。

令人困惑的是,有时当您在 Rust 中使用赋值时,值被复制。例如:

let x = 10;
let y = x;
Run Code Online (Sandbox Code Playgroud)

在 Rust 中执行这些语句后,x 和 y 的值都是 10。在这种情况下,Rust 将该值复制到 y 中。对于简单值,如整数、浮点数、字节、布尔值和共享引用类型,赋值会将值复制到新变量中。

编译器不允许您编写类似以下内容的原因:

fn go(orig: String, orig_ref: &String) {
    println!("{orig}");
    println!("{orig_ref}");
}

fn main(){

    let pig = "pig".to_string();
    let pref = &pig;

    go(pig, pref);

}
Run Code Online (Sandbox Code Playgroud)

是因为调用该函数涉及赋值:

 go(  pig     ,         pref);
       |                |
       V                V
fn go(orig: String, orig_ref: &String)  


    orig = pig      orig_ref = pref
Run Code Online (Sandbox Code Playgroud)

因此,原来的 Stringpig被移入orig,并pig变为“未初始化”。剩下pref指向 的pig内容不再有效。Rust 的创建是为了防止 C++ 错误,例如悬空指针,因此编译器不会让您创建悬空指针。

有关 Python、C++ 和 Rust 如何采用不同方法进行赋值工作的更详细说明,请参阅以下内容:

如何使用 Rust 重用结构体实例

因为你看起来懂C++,所以我们来谈谈指针吧。根据“Programming Rust(修订版第二版)”,字符串类型是一个“胖”指针:它由长度和容量组成,此外还有一个指向实际存储字符串的堆上某些内存的指针。例如,如果你写:

   let pig = "hi".to_string();
Run Code Online (Sandbox Code Playgroud)

那么情况是这样的:

在此输入图像描述

长度是字符串的实际长度,容量是在 Rust 需要为字符串分配更多内存之前分配的内存中总共可以容纳多少个字符。与常规指针一样,“胖”指针的复制效率很高,因为它只有三个“机器字”长——无论堆上分配了多少内存。

那么如果你写:

   let pref = &pig;
Run Code Online (Sandbox Code Playgroud)

我认为发生的事情是这样的: 在此输入图像描述
pref不指向存储字符串的堆上的内存,而是pref指向堆栈上的3字字符串。随后,如果 String inpig被移动到其他地方,即 3 字胖指针被复制到堆栈上的某个其他位置并且 Rust“未初始化” pig,那么pref将成为悬空指针。

Rust 会自动跟踪指向指针的指针链,以便检索实际的字符串,这就是为什么当您编写时:

 println!("{}", pref);
Run Code Online (Sandbox Code Playgroud)

Rust 将输出字符串而不是地址。