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

Explanation of objects moves and borrowings int rev(), chars() and next()

嗨,所有。为了理解移动和借用操作的规则,我编写了以下代码:

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

但这会造成一种奇怪的情况。我希望 & 运算符创建一个借用操作,移动基本上是 Self -> Self 移动。但事实并非如此。如果移动仍然发生,& 会向新移动的对象传递新的引用,还是对象仍然是相同的,只是这个所有权概念开始起作用(所有权从 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()函数的实现好像很正常

在试图弄清楚一个方法是执行移动还是借用时,要注意的一件重要事情是查看它的签名。

&str 上的方法 chars 具有 following signature:

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

正如您在 self 中使用的 & 所见,此方法 借用 它调用的值,以 return名为 Chars 的结构实现了 Iterator 特征(next 方法的来源)。

如果你查看 revsignature,它来自 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方法(在Iterator中定义)returns Option<Self::Item>,而不是迭代器本身。这就是为什么当你修复所有权错误时,你会发现自己在第一次打印时有一个迭代器,而在第二次打印时只有一个 Option 值。

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

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

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

test_chars 移动到 rev,其中 returns 一个新的迭代器被移动到 test_chars_rev.

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

test_chars_1 移动到 rev,其中 returns 一个新的迭代器被移动到一个临时的,然后 next 借用那个临时的 returns 它的第一个移入 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 的类型 Option<&char> 实现了 Copy.