对象移动和借用 int rev()、chars() 和 next() 的解释



Hy, all.在我理解移动和借用操作规则的实验中,我编写了以下代码:

let company:&str="TutorialsPoint";
let test_chars = company.chars(); // move
let test_chars_1 = company.chars(); // move
let test_chars_rev = &test_chars_1.rev(); // move --explicit type here is &std::iter::Rev<std::str::Chars<'_>>
let test_chars_rev_next = test_chars_1.rev().next(); //move --creates an error that the line before a move occurred
let test_chars_rev_next_copy = test_chars_rev_next;
println!("Char indices test reverse: {:?}",  test_chars_rev);
println!("Char indices test reverse: {:?}",  test_chars_rev_next);

现在在我的逻辑中。 下面这行应该是借用而不是移动。

let test_chars_rev = &test_chars_1.rev(); // move

但这造成了一种奇怪的情况。我期望 & 运算符创建一个借用操作,并且移动基本上是自>自移动。但事实似乎并非如此。如果移动仍然发生,那么 & 会为新的移动对象提供新的引用,或者对象是否仍然相同,只是这个所有者船概念开始(所有权从test_chars_1转移到test_chars_rev)?

在这种情况下,我必须如何设想所有权,例如引用被移动,或者编译器中是否有跟踪事物的魔术?

当然,我尝试了以下方案。

let test_chars = company.chars(); // move
let test_chars_1 = company.chars(); // move
let test_chars_rev = test_chars.rev(); // move 
let test_chars_rev_next = test_chars_1.rev().next(); //move
let test_chars_rev_next_copy = test_chars_rev_next;
println!("Char indices test reverse: {:?}",  test_chars_rev);
println!("Char indices test reverse: {:?}",  test_chars_rev_next);

在这里一切正常。但结果有点尴尬。

Char indices test reverse: Rev { iter: Chars(['T', 'u', 't', 'o', 'r', 'i', 'a', 'l', 's', 'P', 'o', 'i', 'n', 't']) }
Char indices test reverse: Some('t')

第二行尤其令人难以置信。我做了一个 next() 操作,突然我没有字符可以写出来,只有 1 个字符。为什么会这样?我看了一下 next() 函数的实现,它似乎很正常。

在尝试确定方法是否执行移动或借用时,要查看其签名的重要事项。

&strchars的方法具有以下签名:

pub fn chars(&self) -> Chars<'_>

正如你从self中使用的&所看到的,这个方法借用了它被调用的值,返回一个名为Chars的结构,它实现了Iterator特征(next方法的来源)。

如果你看一下rev的签名,它来自Iterator特征,你会看到它移动了它所调用的值:

fn rev(self) -> Rev<Self>

另一件需要注意的事情是,将&放在变量之前将提取对它的引用,它不会使操作借用而不是移动。操作移动或借用行为已融入其签名中。

所以发生了什么是这样的:

let company: &str = "TutorialsPoint";
let test_chars = company.chars(); // borrow
let test_chars_1 = company.chars(); // borrow
let test_chars_rev = &test_chars_1.rev(); // move and then `&` extracts a reference
let test_chars_rev_next = test_chars_1.rev().next(); // tries to use a moved value, error (value moved to `test_chars_rev`)
let test_chars_rev_next_copy = test_chars_rev_next;
println!("Char indices test reverse: {:?}",  test_chars_rev);
println!("Char indices test reverse: {:?}",  test_chars_rev_next);

您可以检查对chars的调用是否是借用的,因为您在company上调用了该方法,但之后仍再次使用了company

最后一件事是next方法(在迭代器中定义)返回Option<Self::Item>,而不是迭代器本身。这就是为什么当您修复所有权错误时,您会发现自己在第一次打印时有一个迭代器,在第二次打印时有一个Option值。

let test_chars = company.chars(); // move

借用company,创建一个迭代器并将这个迭代器移动到test_chars

let test_chars_rev = test_chars.rev(); // move 

test_chars移动到rev中,返回移动到test_chars_rev中的新迭代器。

let test_chars_rev_next = test_chars_1.rev().next(); //move

test_chars_1移动到rev中,返回移动到临时迭代器中的新迭代器,然后next借用该临时迭代器并返回移动到test_chars_rev_next中的第一个值。然后丢弃临时。

let test_chars_rev_next_copy = test_chars_rev_next;

test_chars_rev_next复制到test_chars_rev_next_copy中。这是一个副本,而不是移动,因为test_chars_rev_next具有实现CopyOption<&char>类型。

最新更新