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() 函数的实现,它似乎很正常。
在尝试确定方法是否执行移动或借用时,要查看其签名的重要事项。
&str
上chars
的方法具有以下签名:
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
具有实现Copy
的Option<&char>
类型。