为什么Rust的std::iter::zip似乎具有内部可变性?

cx6n0qe3  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(118)

根据我的理解,我不应该对一个不可变的数据块有一个可变的引用。因此,如果我想创建一个struct,它基于内部状态的变化来实现Iterator,那么我必须将该struct的任何示例声明为可变的,以便能够创建所需的可变引用。
为了演示,我构造了一个简单的示例,如下所示:

struct MyIter {
    internal_state: u32
}

impl MyIter {
    fn new() -> MyIter {
        MyIter{ internal_state: 0 }
    }
}

impl Iterator for MyIter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        self.internal_state += 1;
        Some(self.internal_state)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::iter::zip;

    #[test]
    fn mutable_declaration_no_zip() {
        let mut my_iter = MyIter::new();
        assert_eq!(my_iter.next(), Some(1));
        assert_eq!(my_iter.next(), Some(2));
        assert_eq!(my_iter.next(), Some(3));
    }
}

字符串
这可以很好地编译并通过,而如果我将test函数改为具有my_iter的不可变声明,如下所示,那么它将拒绝编译,并返回预期的error[E0596]: cannot borrow 'my_iter' as mutable, as it is not declared as mutable消息:

#[test]
fn immutable_declartaion_no_zip() {
    let my_iter = MyIter::new();
    assert_eq!(my_iter.next(), Some(1));
    assert_eq!(my_iter.next(), Some(2));
    assert_eq!(my_iter.next(), Some(3));
}


我的问题是,如果我做了与上面基本相同的操作,但使用std::iter::zip来执行迭代,那么现在发生的情况是,即使我将my_iter声明为immutable,测试仍然编译并通过,这意味着zip已经改变了我传递给它的immutable变量的状态!

#[test]
fn immutable_declaration_zip() {
    let my_iter = MyIter::new();
    let nums: [u32;10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    for (i, num) in zip(my_iter, nums.iter()) {
        assert_eq!(i, *num);
    }
}


那么,有人能解释一下为什么zip被设置为允许这样做吗?zip如何调用next()方法,从而生成对我声明为不可变的数据的可变引用?

im9ewurl

im9ewurl1#

可变性注解(mut或缺少)跟随变量,而不是值。

let mut my_iter = MyIter::new();

字符串
这里,不是my_itervalue 是可变的,而是my_iter本身。只要my_iter拥有这个值,它就是可变的。所以你可以调用my_iter.next(),这需要一个可变的引用。

let my_iter = MyIter::new();


相同的参数,但没有mut。只要my_iter拥有迭代器,它就是 immutable,所以不允许对它进行可变引用。

  • 然而,* 这里的关键短语是“只要my_iter拥有迭代器”。
zip(my_iter, nums.iter())


std::iter::zipsignature

pub fn zip<A, B>(
    a: A,
    b: B
) -> Zip<<A as IntoIterator>::IntoIter, <B as IntoIterator>::IntoIter>
where
    A: IntoIterator,
    B: IntoIterator,


它通过 value 获取两个参数。当您调用zip时,该函数将获取值的所有权。这意味着 nobody 当前拥有对该值的引用(无论是可变的还是不可变的),而zip可以自由决定它是否可变,因为它现在是独占所有者。

相关问题