我只是一个Rust岁的新秀,我对这一点感到有点困惑.举个例子:

fn func(s_ref: &mut str) {}

fn main() {
    let mut word = "hello".to_string();
    let s: &mut str = &mut word;
    func(s);
}

在讨论Rust之前,我想告诉一些关于C++的事情,以便更好地阐明Rust.

因此,在C++中,如果我们将指针s作为其名为s_ref的参数传递到函数中,那么指针本身将被复制为临时变量,以供调用的函数内部使用,并且当它到达作用域的末尾时,s_ref将自动释放,对吗?

说到铁 rust ,我认为是一样的.因为引用(或指针)是simple data type(像I32一样),所以传递的引用s将是generated a copy,名为s_ref.但如果是这样的话,同一个变量word有两个可变引用,这违反了Rust的定义规则.

我知道我弄错了人,但我不能准确地指出.你能帮个忙吗?非常感谢.

推荐答案

你很接近了,但你遗漏了一个关键的细节.

在Rust中,赋值(包括函数参数的赋值)由值moving进行,除非值的类型实现Copy,在这种情况下它被复制.在C++中,您必须使用std::move()请求MOVE(在它不是隐式的情况下),而在Rust中,对于不能复制的值,MOVE是automatic,并且MOVE会腾出原始变量,因此再次try 从它读取会导致编译时错误.

Copy特征是为所有共享引用(&T)实现的,但它是为可变引用(&mut T)实现的not.

然而,在这种特殊情况下,编译器做了一件狡猾的事情.如果移动了引用,那么在调用func()之后,s将处于"Moving From"状态,因此您可能会认为不能再使用它了……但你可以的!

func(s);
func(s);

这将进行编译.那到底是怎么回事?

编译器会在此处插入一个reborrow,就好像您已经编写了以下代码:

func(&mut *s);

这种构造要求编译器not消费引用s,并且取而代之地重新borrow 其引用.(当传递对函数的引用时,这会隐式发生,就像这里所发生的那样,但在其他情况下,它是not隐式的,您必须显式地重新borrow .)

但如果是这样的话,同一个变量word有两个可变引用,这违反了Rust的定义规则.

啊,但这并不是quite%的规则.规则是,在任何给定时刻,值可以是:

  • 可读任意数量的名称,or
  • 可写入at most one name.

这并不意味着不能有两个对同一个值的可变引用,它只是意味着一次只能有一个可用引用.

在您的代码中,main()在重新borrow s之后将控制权转移给func().这意味着ss_ref离开之前不能使用--但它could not possibly be used直到s_ref离开,因为func()必须在s可以再次使用之前返回.

因此,如您所见,这并不违反Rust的别名规则.调用func()时,可以使用s_ref将值word写入,但在函数返回之前,不能使用s将其写入.那么s就可以再次使用了.

我们可以通过以下两个程序来演示这一点:

fn func(s_ref: &mut str) {}

fn main() {
    let mut word = "hello".to_string();
    let s: &mut str = &mut word;
    
    let s2: &mut str = &mut *s;
    func(s2);
    
    func(s);
}

这是编译的!我们将s重新借入s2,但我们在停止使用s2之前不会使用s.编译器自己计算出这一点(见non-lexical lifetimes).

然而,如果我们交错使用,那么我们就有一个问题:

fn func(s_ref: &mut str) {}

fn main() {
    let mut word = "hello".to_string();
    let s: &mut str = &mut word;
    let s2: &mut str = &mut *s;
    
    func(s);
    func(s2);
}

现在,编译器会抱怨:

error[E0499]: cannot borrow `*s` as mutable more than once at a time
 --> src/main.rs:8:10
  |
6 |     let s2: &mut str = &mut *s;
  |                        ------- first mutable borrow occurs here
7 |     
8 |     func(s);
  |          ^ second mutable borrow occurs here
9 |     func(s2);
  |          -- first borrow later used here

在第6和第9行之间,ss2都被认为是可用的,这是不允许的.

正如您所看到的,对同一个值有多个可变引用是没有问题的.但是,它们的使用不允许重叠.只要它们不重叠,就没有问题.

Rust相关问答推荐

如何在tauri—leptos应用程序中监听后端值的变化?""

收集RangeInclusive T到Vec T<><>

为什么我的梅森素数代码的指数越大,速度就越快?

如何仅使用http机箱发送http请求?

文档示例需要导入相关的 struct ,但仅在运行测试时.这是故意的行为吗?

通过解引用将值移出Box(以及它被脱糖到什么地方)?

如何向下转换到MyStruct并访问Arc Mutex MyStruct实现的方法?

是否可以在不直接重复的情况下为许多特定类型实现一个函数?

如何正确使用git2::Remote::push?

Rust 中的自动取消引用是如何工作的?

push 方法是否取得所有权?

如何刷新 TcpStream

如何展平以下嵌套的 if let 和 if 语句?

第 7.4 章片段中如何定义 `thread_rng`

没有分号的返回表达式的性能是否比使用返回更好?在Rust ?

If let expression within .iter().any

为什么基于 clap::Parser 读取的大量数字进行计算比硬编码该数字时慢?

如何存储返回 Future 的闭包列表并在 Rust 中的线程之间共享它?

Rust HRTB 是相同的,但编译器说一种类型比另一种更通用

你能用 Rust 和 winapi 制作 Windows 桌面应用程序吗?