在不进行其他借用的情况下,在不可变迭代器上运行next时无法作为可变借用进行借用

4
当尝试运行下面的代码时:
fn main() {
    let s1 = String::from("hello world");
    println!("The first word in the string is: {}", return_first_word(&s1));
}

fn return_first_word(s: &String) -> String {
    let t = s.split(" ");
    String::from(t.next().unwrap())
}

我在 String::from(t.next().unwrap()) 这一行代码上得到了一个错误信息 cannot borrow as mutable。当我将这一行中的 let t = ... 替换为 let mut t = ... 后,代码可以正常工作。
我的问题是,有人能解释一下为什么吗?这里借用了什么,是由谁来借用的?我检查了我新创建的不可变变量 t 的类型,它是一个迭代器。为什么在迭代器上进行迭代会有问题呢?

1
Do not post errors as images. - Chayim Friedman
1个回答

10
如果您熟悉像Java这样的语言,您可能会期望str::split返回一个数组,但实际上并不是这样。在Rust中,str::split返回一个迭代器。它实际上并不立即拆分整个字符串;它给你一个特殊的迭代器对象,当你迭代字符串时,它才进行拆分。
现在,在Rust中迭代是一种有状态的过程。要迭代某些内容,您需要调用Iterator::next,它会改变迭代器的内部状态并生成下一个值。如果反复调用,它会按顺序给出迭代器的每个值,然后开始生成None。由于next会改变迭代器的状态,因此必须使用可变引用来引用迭代器。
在Rust中,当您使用let声明变量时,它是不可变的。您不能更改它。您告诉了Rust系统您没有更改它的意图。因此,当您尝试获取对一件事物(在您的情况下是一个迭代器)的可变引用时,Rust会发出警告。相反,您需要使用let mut来说明您的意图。

嘿,我猜想可能是这种情况。很奇怪的是,我居然能够创建一个不可变迭代器,因为它们几乎没有用处,我无法真正地对它们进行迭代,从而使其不成为迭代器!谢谢! - ste_kwr
2
当所有权转移时,值的可变性可能会发生改变。例如,如果您获得一个迭代器,将其存储在变量中,然后将其所有权传递给其他函数,即使您存储它的变量是 let(即不可变的),您提供的函数也可以选择对其进行更改。迭代器本身并不是不可变的,只是在那一刻拥有它的变量是不可变的。 - Silvio Mayolo
啊..谢谢。这让我感到非常清晰明了! - ste_kwr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接