Rust in Everything
#Rust#Iterator#迭代器

Rust迭代器

在Rust中,迭代器是一种尤为重要的数据类型, 被用于遍历集合中的元素。 Rust中的大多数集合类型都可以转换成迭代器, 从而可以对它们进行遍历。 包括:数组(Array)、向量(Vec)、散列表(HashMap)

使用迭代器可以使代码更加简洁、优雅,并且支持 过滤,映射,折叠 等强大的操作

迭代器的基本概念

在Rust中,迭代器是一种实现了Iterator trait的类型。 该trait定义了在集合中遍历元素的一系列行为。 通过实现Iterator trait,可以将一个类型转换为一个迭代器, 从而实现迭代器等操作。

Iterator Trait

Iterator trait定义了迭代器的核心行为。 它包括next方法和其它几个方法。 next方法为集合中的下一个元素返回一个**Option值**, 直到所有元素都遍历完毕,此时返回None。

除了next方法,Iterator trait还定义了许多其他有用的方法, 例如map、filter等,允许对迭代器元素进行操作和转换。

pub trait Iterator {
  type Item;

  fn next(&mut self) -> Option<Self::Item>;
}

Animal案例

让我们探索Animal结构体的迭代器的实现。 Animal类型实现了Iterator trait, 从而可以对其属性进行迭代。 以下是Animal类型的定义:

#[derive(Debug)]
struct Animal {
  name: String,
  age: u32,
  kind: String,
  i: i32,
}

我们为Animal实现Iterator trait,以使用for循环迭代其属性:

impl Iterator for Animal {
  type Item = String;

  fn next(&mut self) -> Option<Self:Item> {
    let next_attribute = match self.i {
      0 => Some(self.name.clone()),
      1 => Some(self.age.to_string()),
      2 => Some(self.kind.clone()),
      _ => None,
    };
    self.i += 1;
    next_attribute
  }
}

现在我们已经将类型转换为迭代器,
我们可以从迭代器中调用各种方法。
例如,可以使用`for`循环来迭代`Animal`的每个属性:

```rust
fn main() {
  let mut animal = Animal {
    name: "Tome".to_string(),
    age: 15,
    kind: "cat".to_string(),
    i: 0,
  }
}

在上述代码中,我们定义了一个Animal的迭代器, 包括一个名为i的内部状态变量。 代码成功打印了Animal的所有信息。

让我们通过定义Animal向量并迭代打印每个Animal的属性来继续我们的探索:

fn print_all_attrs(animals: Vec<Animal>) {
  for mut animal in animals {
    println!("Name: {}", animal.next().unwrap());
    println!("Age : {}", animal.next().unwrap());
    println!("Kind: {}", animal.next().unwrap());
  }
}

fn main() {
  let animals = vec![Animal {
    name: "Tom".to_string(),
    age: 15,
    kind: "cat".to_string(),
    i: 0,
  }];
  print_all_attrs(animals);
}

在这段代码中,我们使用for循环来迭代所有Animal对象并逐一打印它们的属性。

迭代器的常见用途

map方法

map方法是Iterator trait中的一个关键方法。 它允许我们转换迭代器中的每个元素并返回一个新的迭代器。 例如:

fn main() {
  let animals = vec![
    Animal {
      name: "Tom".to_string(),
      age: 14,
      kind: "cat".to_string(),
      i: 0,
    },
    Animal {
      name: "Jerry".to_string(),
      age: 7,
      kind: "mouse".to_string(),
      i: 1,
    },
  ];

  let list: Vec<String> = animals
    .into_iter()
    .map(|ani| ani.name.clone())
    .collect();
  println!("{:?}", list); 
}

在上面的代码中,我们定义了一个带有两个Animal对象的向量, 并使用map方法从每个Animal中提取name属性, 返回一个新的迭代器。 然后,collect()方法将其转换为向量。

filter方法

假设我们想找到三岁或以上的Animal。 我们可以使用过滤器来实现这一点:

fn main() {
  let animals = vec![
    Animal {
      name: "Tom".to_string(),
      age: 33,
      kind: "cat".to_string(),
      i: 3,
    },
  ];

  let filtered_animals: Vec<Animal> = animals
    .into_iter()
    .filter(|animal| animal.age >= 3)
    .collect();
  println!("{:?}", filtered_animals);
}

在上面的代码中,我们使用filter方法选择年龄为三岁或以上的Animal, 返回一个新的Animal向量。

enumerate方法

enumerate方法将迭代器中的每个元素与其索引配对, 返回一个新的迭代器。例如:

fn main() {
  let animals = vec![
    Animal {
      name: "Tom".to_string(),
      age: 33,
      kind: "cat".to_string(),
      i: 3,
    },
    Animal {
      name: "Jay".to_string(),
      age: 22,
      kind: "mouse".to_string(),
      i: 4,
    },
  ];

  for (i, animal) in animals.iter().enumerate() {
    println!("{}: {:?}", i, animal);
  }
}

在上面代码中,我们使用enumerate方法将每个Animal与其索引配对, 并使用for循环打印结果。

flat_map方法

flat_map方法不太常见但很有用。 它展平嵌套迭代器到单个迭代器中。例如:

fn main() {
  let cat = Animal {
    name: "Tom".to_string(),
    age: 21,
    kind: "cat".to_string(),
    i: 3,
  };

  let mouse = Animal {
    name: "Jerry".to_string(),
    age: 3,
    kind: "mouse".to_string(),
    i: 2,
  };

  let animals = vec![vec![cat], vec![mouse]];

  let list: Vec<Animal> = animals
    .iter()
    .flat_map(|x| x.iter().cloned())
    .collect();
  println!("{:?}", list);
}

在上面代码中,我么定义了一个2D向量Animals,并使用flat_map方法 将其展平为1D迭代器,将其转换回向量。

zip方法

要同时迭代两个向量,我们可以使用zip方法进行配对:

fn main() {
  let names = vec!["Tom", "Jerry", "Bob"];
  let ages = vec![3, 4, 5];

  for (name, age) in names.iter().zip(ages.iter()) {
    println!("{} is {} years old", name, age);
  }
}

在上面代码中,我们使用zip方法将姓名和年龄向量中的元素配对, 并在for循环中打印每对。

fold方法

fold方法在Rust中时必不可少的; 它接受一个初始值和一个闭包, 迭代元素, 并将它们合并为一个值。例如:

fn main() {
  let cat = Animal {
    name: "Tom".to_string(),
    age: 13,
    kind: "cat".to_string(),
    i: 0,
  };
  let mouse = Animal {
    name: "Jerry".to_string(),
    age: 7,
    kind: "mouse".to_string(),
    i: 1,
  };

  let animals = vec![cat, mouse];

  let sum = animals
    .iter()
    .fold(0, |t, ani| t + ani.age);
  println!("{}", sum);
}

在上面代码中,我们定义了一个带有两个Animal对象的向量, 并使用fold方法累加年龄属性, 返回结果总和。

总结

在Rust中,迭代器是遍历集合元素和支持各种操作的重要数据类型。 在本文中,我们探讨了迭代器的基本概念和常用方法, 并使用Animal示例演示了相应的代码。 希望读者能够扎实地理解Rust迭代器,并在实际编程中有效地应用它们。

评论区

登录后即可发表评论

加载评论中…

💬 关联讨论

发起讨论
加载中...