< 返回版块

eric642 发表于 2021-12-19 20:18

关于 Rust程序设计语言 这本的一个问题

书里有一段是:

这些调用 next 方法的方法被称为 消费适配器(consuming adaptors),因为调用他们会消耗迭代器。一个消费适配器的例子是 sum 方法。这个方法获取迭代器的所有权并反复调用 next 来遍历迭代器,因而会消费迭代器。当其遍历每一个项时,它将每一个项加总到一个总和并在迭代完成时返回总和。示例 13-16 有一个展示 sum 方法使用的测试:

文件名: src/lib.rs

#[test]
fn iterator_sum() {
    let v1 = vec![1, 2, 3];

    let v1_iter = v1.iter();

    let total: i32 = v1_iter.sum();

    assert_eq!(total, 6);
}

v1_iter是不可变的, 而书中前面说过netx方法是需要可变引用的, 这里sum方法里面是怎么做到可以调用next的.

评论区

写评论
苦瓜小仔 2021-12-20 02:19

你还可以从模式的角度理解所有权和可变性。Rust 的模式出现在以下地方:

  • let declarations
  • Function and closure parameters
  • match expressions
  • if let expressions
  • while let expressions
  • for expressions

什么是模式?

Patterns are used to match values against structures and to, optionally, bind variables to values inside these structures. They are also used in variable declarations and parameters for functions and closures.

比如以下代码:

fn main() {
    {
        let s = "string".into();
        f(s);
    }
    // 以上代码等价于以下代码
    {
        let s: String = "string".into();
        {
            let mut a = s; // let 声明中的模式
            a += "s";
            assert_eq!(a, "strings");
        }
    }
}

fn f(mut a: String) { // 函数参数中的模式
    a += "s";
    assert_eq!(a, "strings");
}

作为参数传给函数和使用 let 从形式上看如出一辙,功能上毫无差别:你把数据的所有权转交出去,和 数据以新的、可变(独占)或者不可变(共享)方式使用,并不冲突。

作者 eric642 2021-12-19 23:59

一开始想的是如果一个变量一开始设置为不可变, 那么所有权转移后, 应该也是不可变的.

但是其实是否可变是一个概念, 所有权是一个概念.

所有权是 是否拥有这个变量.

是否可变 是在一个作用域内和相关上下文里表示我这段代码里的这个变量是否可变.

拥有所有权的代码可以重新设置是否可变.

作者 eric642 2021-12-19 23:55

嗯嗯, 理解了. 我把所有权和是否可变混为一谈了. 谢谢大佬.

--
👇
c5soft: 所有权移交后,可变不可变就由接收方自行处理了。

作者 eric642 2021-12-19 23:55

嗯嗯, 明白了. 所有权转移下, 是否可变就可以重新设置了. 谢谢大佬

--
👇
viruscamp: v1_iter 是不可变的,但是调用 sum 的时候 move 进 sum 变成 sum 里的一个 mut 变量了啊。 就像

struct A(i32);

fn move_mut(mut b: A) {
  // b 是可变的
}

fn main() {
  let a = A(8);// a 是不可变的
  move_mut(a); // 作为参数 move 给函数调用
}
viruscamp 2021-12-19 23:41

v1_iter 是不可变的,但是调用 sum 的时候 move 进 sum 变成 sum 里的一个 mut 变量了啊。 就像

struct A(i32);

fn move_mut(mut b: A) {
  // b 是可变的
}

fn main() {
  let a = A(8);// a 是不可变的
  move_mut(a); // 作为参数 move 给函数调用
}
c5soft 2021-12-19 23:37

所有权移交后,可变不可变就由接收方自行处理了。

c5soft 2021-12-19 23:32

调用迭代器的next()才需要对变量做mut声明,为什么?去看看next调用的声明的说明或者源代码就清楚了。sum调用后果相当于std::mem::drop。

作者 eric642 2021-12-19 22:19

有点纠结, 内部是通过unsafe再去转换的吗, 一开始迭代器就声明成了不可变的.

--
👇
c5soft: sum函数的签名是:fn sum(self) -> S,不是 fn sum(&mut self) -> S,调用sum的时候v1_iter的所有权完全转移到sum内部,调用sum后v1_iter不能再用,所以不需要申明为 let mut v1_iter = v1.iter()。 换一种理解思路:sum拿到v1_iter后,内部会将v1_iter变成mut变量。可以理解为下面这样一段虚拟的代码:

fn sum(self:impl Iterator<Item=i32>) -> i32 {
  let mut sum=0;
  let mut self=self;
  while Some(v)=self.next() {
    sum+=v;
  }
  sum
}
c5soft 2021-12-19 21:48

sum函数的签名是:fn sum(self) -> S,不是 fn sum(&mut self) -> S,调用sum的时候v1_iter的所有权完全转移到sum内部,调用sum后v1_iter不能再用,所以不需要申明为 let mut v1_iter = v1.iter()。 换一种理解思路:sum拿到v1_iter后,内部会将v1_iter变成mut变量。可以理解为下面这样一段虚拟的代码:

fn sum(self:impl Iterator<Item=i32>) -> i32 {
  let mut sum=0;
  let mut self=self;
  while Some(v)=self.next() {
    sum+=v;
  }
  sum
}
1 共 9 条评论, 1 页