{"id":14110300,"url":"https://github.com/rustomax/rust-iterators","last_synced_at":"2026-01-17T14:18:01.875Z","repository":{"id":50520965,"uuid":"65589294","full_name":"rustomax/rust-iterators","owner":"rustomax","description":"Basic Rust iterator usage","archived":false,"fork":false,"pushed_at":"2021-10-20T19:39:30.000Z","size":79,"stargazers_count":256,"open_issues_count":0,"forks_count":21,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-11-29T10:54:20.706Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rustomax.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-12T23:31:39.000Z","updated_at":"2024-07-28T18:22:50.000Z","dependencies_parsed_at":"2022-09-03T17:02:24.738Z","dependency_job_id":null,"html_url":"https://github.com/rustomax/rust-iterators","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustomax%2Frust-iterators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustomax%2Frust-iterators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustomax%2Frust-iterators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustomax%2Frust-iterators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rustomax","download_url":"https://codeload.github.com/rustomax/rust-iterators/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228369076,"owners_count":17909188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-14T10:02:46.519Z","updated_at":"2026-01-17T14:18:01.867Z","avatar_url":"https://github.com/rustomax.png","language":"Rust","funding_links":[],"categories":["Rust","Summary"],"sub_categories":[],"readme":"# rust-iterators\n\nThis tutorial demonstrates basic Rust iterator use with modern idioms and additional techniques. It's goal is to provide a handy reference to some common iterator patterns.\n\n\u003e To take full advantage of the material described here, it is recommended that you have at least cursory familiarity with Rust.\n\nHow to compile and run sample code:\n\n```sh\ngit clone https://github.com/rustomax/rust-iterators.git\ncd rust-iterators/\ncargo run\n```\n\n## Contents\n\n- [Introduction](#introduction)\n- [Basic Ranges](#basic-ranges)\n- [Digging Deeper](#digging-deeper)\n- [Iterating over Arrays](#iterating-over-arrays)\n- [Combining Iterator Adaptors](#combining-iterator-adaptors)\n- [Ranges of Characters](#ranges-of-characters)\n- [Iterating over Vectors](#iterating-over-vectors)\n- [Creating Iterators from Collections - A Summary](#creating-iterators-from-collections---a-summary)\n- [Infinity and Beyond](#infinity-and-beyond)\n- [Itertools](#itertools)\n- [Additional Iterator Adaptors](#additional-iterator-adaptors)\n- [Creating Your Own Iterators](#creating-your-own-iterators)\n- [Conclusion](#conclusion)\n\n## Introduction\n\nLife is repetitive, and most things in it come as series of items. Programmatically, we often need to count, enumerate, and iterate over these sequences. Many languages use the familiar C-style `for` loop:\n\n```c\nfor ( x = 0; x \u003c 10; ++x ) {\n  // do something\n}\n```\n\nWhile this method is powerful, it can be prone to errors like off-by-one bugs or unintended mutation of the iterator variable. In keeping with Rust’s safety and consistency, there is no C-style `for` loop. Instead, Rust leverages *iterators* to achieve these goals—and much more.\n\n## Basic Ranges\n\nThe simplest way to loop over a series of integers in Rust is with a range. The range created using `..` produces an iterator of integers incremented by `1`:\n\n```rust\nfor i in 1..11 {\n    print!(\"{} \", i);\n}\n// output: 1 2 3 4 5 6 7 8 9 10\n```\n\nNote that `1..11` is inclusive at the start and exclusive at the end. If you want a range that includes both endpoints, use the `..=` notation:\n\n```rust\nfor i in 1..=10 {\n  print!(\"{} \", i);\n}\n// output: 1 2 3 4 5 6 7 8 9 10\n```\n\nIf you do not use the loop variable, you can simply use the `_` pattern:\n\n```rust\nlet mut n: i32 = 0;\nfor _ in 0..10 {\n  n += 1;\n}\nprintln!(\"num = {}\", n);\n// output: num = 10\n```\n\nOr even more idiomatically, use the iterator’s built-in `count()`:\n\n```rust\nprintln!(\"num = {}\", (0..10).count());\n// output: num = 10\n```\n\n\u003e Experienced Rust programmers often express logic in terse iterator language, turning what might have been several lines of code into a concise chain of adaptors and consumers.\n\n## Digging Deeper\n\nSometimes a basic range isn’t enough. Rust lets you customize your iterator in many ways.\n\n### Stepping Through a Range\n\nUse `step_by()` to increment by a value other than 1:\n\n```rust\nfor i in (0..11).step_by(2) {\n    print!(\"{} \", i);\n}\n// output: 0 2 4 6 8 10\n```\n\nAlternatively, use `filter()` to achieve similar results. For example, to iterate over even numbers between 0 and 20:\n\n```rust\nfor i in (0..21).filter(|x| x % 2 == 0) {\n  print!(\"{} \", i);\n}\n// output: 0 2 4 6 8 10 12 14 16 18 20\n```\n\nOr combine conditions:\n\n```rust\nfor i in (0..21).filter(|x| x % 2 == 0 \u0026\u0026 x % 3 == 0) {\n  print!(\"{} \", i);\n}\n// output: 0 6 12 18\n```\n\n### Reversing and Mapping\n\nReverse a range with `rev()`:\n\n```rust\nfor i in (0..11).rev() {\n  print!(\"{} \", i);\n}\n// output: 10 9 8 7 6 5 4 3 2 1 0\n```\n\nApply a function to each element with `map()`:\n\n```rust\nfor i in (1..11).map(|x| x * x) {\n    print!(\"{} \", i);\n}\n// output: 1 4 9 16 25 36 49 64 81 100\n```\n\nAnd use `fold()` to reduce the iterator to a single value:\n\n```rust\nlet result = (1..=5).fold(0, |acc, x| acc + x * x);\nprintln!(\"result = {}\", result);\n// output: result = 55\n```\n\nPerhaps the easiest way to understand what is happening here is to rewrite the example above in a more procedural fashion:\n\n```rust\nlet mut acc = 0;\nfor x in 1..=5 {\n  acc += x * x;\n}\nprintln!(\"result = {}\", acc);\n// output: result = 55\n```\n\nWow! Isn't the `fold()` version so much more concise and readable?\n\n## Iterating over Arrays\n\nIn the past, you had to explicitly call `.iter()` to iterate over an array. Now, arrays in Rust implement `IntoIterator` directly, for example:\n\n```rust\nlet cities = [\"Toronto\", \"New York\", \"Melbourne\"];\n\nfor city in cities {\n  print!(\"{}, \", city);\n}\n// output: Toronto, New York, Melbourne,\n```\n\nIt's important to understand what is happening under the hood here. When you iterate over the array directly, the array’s `into_iter()` method is called. If the elements implement the `Copy` trait, they are copied into the loop variable. In the example above, each city is a string slice (`\u0026str`), which implements `Copy`, so during iteration, each city is copied into the variable `city`. This is safe and efficient because string slices are lightweight and implement the `Copy` trait. The array will still be accessible after the iteration, because its elements are copied, not moved. For types that don’t implement `Copy`, such as `String`, the Rust complier doesn't have a choice but to `move` the elements out of the array during iteration, meaning you lose ownership in the original array. In other words, direct iteration over non-`Copy` types, consumes the array. The array becomes unusable after the iteration.\n\nSometimes you might want to avoid copying or moving the elements altogether, especially if the elements are larger or if they do not implement `Copy`. In that case, you iterate over references to the array elements. You can do this in one of two ways:\n\n**1. Using `.iter()`**\n\n```rust\nlet cities = [\n    String::from(\"Toronto\"),\n    String::from(\"New York\"),\n    String::from(\"Melbourne\"),\n];\n\nfor city in cities.iter() {\n    // Here, `city` is a reference to a String (\u0026String), so the values aren’t moved.\n    print!(\"{}, \", city);\n}\nprintln!();\n// output: Toronto, New York, Melbourne,\n```\n\n**2. Using the `\u0026` reference operator**\n\n```rust\nlet cities = [\n    String::from(\"Toronto\"),\n    String::from(\"New York\"),\n    String::from(\"Melbourne\"),\n];\n\nfor city in \u0026cities {\n    // This is equivalent to calling cities.iter().\n    print!(\"{}, \", city);\n}\nprintln!();\n// output: Toronto, New York, Melbourne,\n```\n\nUsing either approach, the original `cities` array remains intact because you’re only borrowing the elements rather than moving them.\n\n## Combining Iterator Adaptors\n\nThe real power of Rust shines when you start combining iterator methods.\n\n### Complex Chains\n\nFor example, to create an inclusive range from 10 down to 0 in steps of 2:\n\n```rust\nfor i in (0..=10).rev().filter(|x| x % 2 == 0) {\n  print!(\"{} \", i);\n}\n// output: 10 8 6 4 2 0\n```\n\nCombine two non-adjacent ranges with `chain()`:\n\n```rust\nlet c = (1..4).chain(6..9);\n\nfor i in c {\n  print!(\"{} \", i);\n}\n// output: 1 2 3 6 7 8\n```\n\nAnd here’s a creative mix of incremented and reversed ranges:\n\n```rust\nlet r = (1..20)\n  .filter(|\u0026x| x % 5 == 0)\n  .chain((6..9).rev());\n\nfor i in r {\n  print!(\"{} \", i);\n}\n// output: 5 10 15 8 7 6\n```\n\n### Zipping Iterators\n\nThe `zip()` adaptor combines two iterators into one of tuples:\n\n```rust\nlet cities = [\"Toronto\", \"New York\", \"Melbourne\"];\nlet populations = [2_615_060, 8_550_405, 4_529_500];\n\nlet matrix = cities.iter().zip(populations.iter());\n\nfor (c, p) in matrix {\n  println!(\"{:10}: population = {}\", c, p);\n}\n// output:\n// Toronto   : population = 2615060\n// New York  : population = 8550405\n// Melbourne : population = 4529500\n```\n\n### Advanced Combinators\n\nConsider also these helpful methods:\n- **`find()`**: Returns the first element matching a predicate.\n- **`find_map()`**: Combines filtering and mapping.\n- **`partition()`**: Splits the elements into two groups based on a predicate.\n\nA quick example of `find()`:\n\n```rust\nlet nums = [1, 3, 5, 7, 8, 9];\nif let Some(even) = nums.iter().find(|\u0026\u0026x| x % 2 == 0) {\n    println!(\"Found even number: {}\", even);\n}\n// output: Found even number: 8\n```\n\n## Ranges of Characters\n\nFor programs that manipulate text, iterating over a range of characters can be useful. The [char_iter crate](https://docs.rs/char-iter/0.1.0/char_iter/) provides a convenient way to generate such ranges (supporting Unicode).\n\nAdd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\nchar-iter = \"0.1\"\n```\n\nThen generate a character range:\n\n```rust\nuse char_iter::new;\n\nfor c in new('Д', 'П') {\n  print!(\"{} \", c);\n}\n// output: Д Е Ж З И Й К Л М Н О П\n```\n\n## Iterating over Vectors\n\nVectors are a fundamental collection in Rust. They can be used with many iterator methods.\n\n### Borrowing Patterns\n\nIterate immutably with `.iter()` or, more succinctly, by borrowing with `\u0026`:\n\n```rust\nlet nums = vec![1, 2, 3, 4, 5];\nfor i in \u0026nums {\n   print!(\"{} \", i);\n}\n// output: 1 2 3 4 5\n```\n\nIf you need to modify elements, use a mutable borrow:\n\n```rust\nlet mut nums = vec![1, 2, 3, 4, 5];\nfor i in nums.iter_mut() {\n    *i *= 2;\n}\nprintln!(\"{:?}\", nums);\n// output: [2, 4, 6, 8, 10]\n```\n\nIf you wish to consume the vector (taking ownership of its elements), use `.into_iter()`:\n\n```rust\nlet nums = vec![1, 2, 3, 4, 5];\nfor i in nums.into_iter() {\n    println!(\"{}\", i);\n}\n```\n\n### Converting Iterators Back into Collections\n\nUse `collect()` to create a vector from an iterator. In many cases, type inference can handle the type, but you can also annotate it:\n\n```rust\nlet v: Vec\u003ci32\u003e = (1..11).collect();\nprintln!(\"{:?}\", v);\n// output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n\n### Converting References to Owned Values\n\nWhen your iterator yields references, but you need owned values (for example, to pass to a function that takes ownership, or to build a new collection of owned items), you can use `.copied()` and `.cloned()` helper methods to transform each item into either a copy or a clone respectively. \n\n```rust\nlet cities = [\"Toronto\", \"New York\", \"Melbourne\"];\nfor city in cities.iter().copied() {\n    println!(\"{}\", city);\n}\n```\n\n\u003e Naturally, you'd use `copied()` for items that implement `Copy`, and `cloned()` for items that implement `Clone`\n\n### Other Useful Methods\n\nGet both index and value with `enumerate()`:\n\n```rust\nlet v = vec![1, 2, 3];\nfor (i, n) in v.iter().enumerate() {\n    println!(\"v[{}] = {}\", i, n);\n}\n// output:\n// v[0] = 1\n// v[1] = 2\n// v[2] = 3\n```\n\nFind minimum or maximum elements:\n\n```rust\nlet v = vec![3, 5, 0, -2, 3, 4, 1];\nlet max = v.iter().max();\nlet min = v.iter().min();\n\nprintln!(\"max = {:?}, min = {:?}\", max, min);\n// output: max = Some(5), min = Some(-2)\n```\n\nAnd sum elements easily:\n\n```rust\nlet grades = vec![4, 5, 6, 9, 7, 4, 8];\nlet sum: i32 = grades.iter().sum();\nlet gpa = sum as f32 / grades.len() as f32;\n\nprintln!(\"sum = {}, gpa = {:.2}\", sum, gpa);\n// output: sum = 43, gpa = 6.14\n```\n\n## Creating Iterators from Collections - A Summary\n\nIf all these ways of creating iterators from collections are confusing, don't worry! Here's a summary of the most common iterator conversion methods in Rust, along with examples and guidance on when to use each one.\n\n### `iter()`\n\n- **What It Does:**  \n  The `.iter()` method creates an iterator that borrows each element of the collection as a reference. In other words, it produces items of type `\u0026T`.\n\n- **When to Use It:**  \n  Use `.iter()` when you want to read from a collection without taking ownership of its elements. This is ideal when the elements are large, non-`Copy`, or when you need to use the collection later.\n\n- **Example:**\n\n  ```rust\n  let numbers = vec![1, 2, 3, 4, 5];\n  \n  // Borrow each element (immutable reference)\n  for num in numbers.iter() {\n      println!(\"Number: {}\", num);\n  }\n  \n  // The original vector is still available here\n  println!(\"Numbers: {:?}\", numbers);\n  ```\n\n### `into_iter()`\n\n- **What It Does:**  \n  The `.into_iter()` method creates an iterator that *consumes* the collection. It takes ownership of the collection and produces items of type `T` (the owned type). For some collections (like arrays), the behavior can vary slightly, but for common collections like `Vec\u003cT\u003e`, it consumes the vector.\n\n- **When to Use It:**  \n  Use `.into_iter()` when you want to move the elements out of the collection, and you no longer need to use the original collection afterward.\n\n- **Example:**\n\n  ```rust\n  let numbers = vec![1, 2, 3, 4, 5];\n  \n  // Consume the vector; items are owned\n  for num in numbers.into_iter() {\n      println!(\"Owned number: {}\", num);\n  }\n  \n  // `numbers` cannot be used here anymore because it was moved.\n  ```\n\n  \u003e **Note:** When used on a type that implements `Copy`, like an array of integers or string slices, the behavior might be less noticeable because the elements are copied rather than moved.\n\n### `iter_mut()`\n\n- **What It Does:**  \n  The `.iter_mut()` method creates an iterator that gives mutable references to each element (`\u0026mut T`). This allows you to modify the elements in place.\n\n- **When to Use It:**  \n  Use `.iter_mut()` when you want to change the elements of a collection while iterating over them.\n\n- **Example:**\n\n  ```rust\n  let mut numbers = vec![1, 2, 3, 4, 5];\n  \n  // Get a mutable reference to each element\n  for num in numbers.iter_mut() {\n      *num *= 2; // double each element\n  }\n  \n  println!(\"Modified numbers: {:?}\", numbers);\n  ```\n\n## Infinity and Beyond\n\nSo far we have dealt with iterators that operated on some finite range of values. Rust generalizes iterators in such a way that it is in fact possible to create an infinite range! Let us consider the following example:\n\n```rust\nlet r = (1..).collect::\u003cVec\u003ci32\u003e\u003e();\n```\n\nThe `(1..)` defines a range that starts with 1 and increments indefinitely. In practice, such program compiles and runs, but eventually crashes with the error message: `fatal runtime error: out of memory`. Well, that's not very practical, you might say. Indeed, by themselves infinite ranges are pretty useless. What makes them useful is combining them with other adaptors and consumers.\n\nOne particularly helpful pattern involves using the `take()` method to limit the number of items returned by the iterator. The following iterator will return the first 10 items in a sequence of squares of integers that are divisible by 5 without a remainder.\n\n```rust\nlet v = (1..)\n  .map(|x| x * x)\n  .filter(|x| x % 5 == 0)\n  .take(10)\n  .collect::\u003cVec\u003ci32\u003e\u003e();\n\nprintln!(\"{:?}\", v);\n// output: [25, 100, 225, 400, 625, 900, 1225, 1600, 2025, 2500]\n```\n\n## Itertools\n\nThe [itertools crate](https://docs.rs/itertools/0.14.0/itertools) offers extra iterator adaptors and methods. Add it to your `Cargo.toml`:\n\n```toml\n[dependencies]\nitertools = \"0.14.0\"\n```\n\nThen import it in your code:\n\n```rust\nuse itertools::Itertools;\n```\n\n### Unique Elements\n\nEliminate duplicates (even if non-sequential):\n\n```rust\nuse itertools::Itertools;\n\nlet data = vec![1, 4, 3, 1, 4, 2, 5];\nlet unique = data.iter().unique();\n\nfor d in unique {\n  print!(\"{} \", d);\n}\n// output: 1 4 3 2 5\n```\n\n### Joining Elements\n\nCombine iterator elements into a single string with a separator:\n\n```rust\nuse itertools::Itertools;\n\nlet creatures = vec![\"banshee\", \"basilisk\", \"centaur\"];\nlet list = creatures.iter().join(\", \");\nprintln!(\"In the enchanted forest, we found {}.\", list);\n// output: In the enchanted forest, we found banshee, basilisk, centaur.\n```\n\n### Custom Sorting\n\nSort elements using a custom comparator with `sorted_by()`:\n\n```rust\nuse itertools::Itertools;\n\nlet happiness_index = vec![\n    (\"Canada\", 7), (\"Iceland\", 4), (\"Netherlands\", 6),\n    (\"Finland\", 1), (\"New Zealand\", 8), (\"Denmark\", 3),\n    (\"Norway\", 2), (\"Sweden\", 9), (\"Switzerland\", 5)\n];\n\nlet top_countries = happiness_index\n  .into_iter()\n  .sorted_by(|a, b| a.1.cmp(\u0026b.1))\n  .take(5);\n\nfor (country, rating) in top_countries {\n  println!(\"# {}: {}\", rating, country);\n}\n\n// output:\n// # 1: Finland\n// # 2: Norway\n// # 3: Denmark\n// # 4: Iceland\n// # 5: Switzerland\n```\n\n## Additional Iterator Adaptors\n\nHere are a few more adaptors that are handy to know:\n\n### `filter_map()`\n\nCombines filtering and mapping:\n\n```rust\nlet numbers = vec![\"1\", \"two\", \"3\", \"four\"];\nlet parsed: Vec\u003ci32\u003e = numbers\n    .iter()\n    .filter_map(|s| s.parse().ok())\n    .collect();\nprintln!(\"{:?}\", parsed);\n// output: [1, 3]\n```\n\n### `take_while()` and `skip()`\n\nThese allow you to process elements conditionally. For example, take elements while they are less than 5:\n\n```rust\nlet nums = vec![1, 2, 3, 4, 5, 6, 7];\nlet taken: Vec\u003c_\u003e = nums.into_iter().take_while(|\u0026x| x \u003c 5).collect();\nprintln!(\"{:?}\", taken);\n// output: [1, 2, 3, 4]\n```\n\n### `inspect()`\n\nUse `inspect()` for debugging—peek at each value without modifying it:\n\n```rust\n(1..5)\n  .inspect(|x| println!(\"About to process: {}\", x))\n  .for_each(|x| println!(\"Got: {}\", x));\n```\n\n## Creating Your Own Iterators\n\nOne of Rust’s strengths is the ability to create custom iterators. In this example, we create an iterator that produces pairs of temperatures in Fahrenheit and Celsius using the formula:  `°C = (°F - 32) / 1.8`.\n\n### Defining the Iterator\n\nAn iterator starts with a struct. Whatever we name the struct will also be the name of the iterator. We will call ours `FahrToCelc`. The struct contains fields that hold useful information that persists between subsequent iterator calls. We will have two `f32` fields - the temperature in Fahrenheit, and the increment step.\n\n```rust\nstruct FahrToCelc {\n  fahr: f32,\n  step: f32,\n}\n```\n\nNext, we will create a convenience method new() that initializes the iterator by passing it initial values for temperature in Fahrenheit and the increment step. This method is strictly speaking not necessary and is not part of the iterator implementation, but I find it to be a nice syntactic sugar that improves overall program readability.\n\n```rust\nimpl FahrToCelc {\n  fn new(fahr: f32, step: f32) -\u003e FahrToCelc {\n    FahrToCelc { fahr, step }\n  }\n}\n```\n\n### Implementing the Iterator Trait\n\n\u003e In Rust, traits are a way of defining shared behavior. Think of a trait as a promise or a set of rules: if a type implements a trait, it guarantees that it provides certain methods. This is similar to interfaces in other languages.\n\nThe Iterator trait is one of the most central traits in Rust. It requires that a type implement the following method:\n\n```rust\nfn next(\u0026mut self) -\u003e Option\u003cSelf::Item\u003e\n```\n\n* `next()`: Returns an Option—either `Some(item)` if there’s another element in the sequence, or `None` if the iterator is finished.\n* `Self::Item`: The type of item the iterator yields.\n\nIn our case, the `Item` type is `(f32, f32)` because we will return pairs of Fahrenheit and Celsius temperatures.\n\nLet's go ahead and implement the `Iterator` trait for our operator.\n\n```rust\nimpl Iterator for FahrToCelc {\n  type Item = (f32, f32);\n\n  fn next(\u0026mut self) -\u003e Option\u003cSelf::Item\u003e {\n    let curr_fahr = self.fahr;\n    let curr_celc = (self.fahr - 32.0) / 1.8;\n    self.fahr += self.step;\n    Some((curr_fahr, curr_celc))\n  }\n}\n```\n\n### Complete Program\n\n```rust\nstruct FahrToCelc {\n  fahr: f32,\n  step: f32,\n}\n\nimpl FahrToCelc {\n  fn new(fahr: f32, step: f32) -\u003e FahrToCelc {\n    FahrToCelc { fahr, step }\n  }\n}\n\nimpl Iterator for FahrToCelc {\n  type Item = (f32, f32);\n\n  fn next(\u0026mut self) -\u003e Option\u003cSelf::Item\u003e {\n    let curr_fahr = self.fahr;\n    let curr_celc = (self.fahr - 32.0) / 1.8;\n    self.fahr += self.step;\n    Some((curr_fahr, curr_celc))\n  }\n}\n\nfn main() {\n  // Start at 0°F with a step of 5°F.\n  let ftc = FahrToCelc::new(0.0, 5.0);\n\n  // Take the first 5 values.\n  let temp_table = ftc.take(5);\n\n  // Print the temperature table.\n  for (f, c) in temp_table {\n    println!(\"{:7.2} °F = {:7.2} °C\", f, c);\n  }\n}\n\n// output:\n//   0.00 °F =  -17.78 °C\n//   5.00 °F =  -15.00 °C\n//  10.00 °F =  -12.22 °C\n//  15.00 °F =   -9.44 °C\n//  20.00 °F =   -6.67 °C\n```\n\n### Other Common Iterator Traits\n\nRust provides additional iterator-related traits that can enhance or further specify an iterator’s behavior:\n\n* `DoubleEndedIterator`: This trait is for iterators that can be run from both ends. In addition to `next()`, they implement a method called `next_back()` which returns the next item from the end. For instance, the `rev()` method on an iterator works because many iterators also implement `DoubleEndedIterator`.\n\n* `ExactSizeIterator`: If an iterator knows exactly how many items it contains, it can implement `ExactSizeIterator`. This provides the `len()` method, which returns the exact number of remaining elements. This is useful when you need to preallocate space or perform other size-dependent operations.\n\n* `FusedIterator`: Once an iterator that implements `FusedIterator` returns None from `next()`, it will always return None on every subsequent call. This guarantees predictable behavior after the iterator is exhausted and can allow for certain compiler optimizations.\n\n## Conclusion\n\nRust iterators empower you to write concise, expressive, and safe code by transforming how you handle sequences of data. Whether you're using built-in adaptors like `map()`, `filter()`, and `fold()`, combining multiple methods with `chain()` or `zip()`, or even creating your own custom iterators, you have a flexible toolkit at your disposal.\n \nBy understanding when to use `.iter()`, `.into_iter()`, or `.iter_mut()`, you can precisely control ownership and borrowing, ensuring your code is both efficient and bug-free. Experiment with these patterns in your own projects and discover just how much simpler and more elegant your iteration logic can become. \n\nFinally, Rust iterators are more than just a convenient way to loop over collections—they are low-cost (or even zero-cost) abstractions. This means that the performance of iterator-based code is comparable to handwritten loops, thanks to aggressive inlining and optimizations performed by the Rust compiler. By using iterators, you write clear code without sacrificing runtime efficiency.\n\nHappy iterating!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustomax%2Frust-iterators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frustomax%2Frust-iterators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustomax%2Frust-iterators/lists"}