Rust入門之迭代器(Iterators)

Rust入門之迭代器(Iterators)

本文已同步本人博客網站
本文相關源碼已上傳Github

前言

迭代器(Iterators)是 Rust 中最核心的工具之一,它不僅是遍歷集合的抽象,更是 Rust 零成本抽象(Zero-Cost Abstractions)和所有權系統完美結合的典范。與其他語言不同,Rust 的迭代器在提供高效遍歷能力的同時,通過編譯器的嚴格檢查,確保內存安全和性能優化,從而避免了其他語言中常見的迭代器失效或越界訪問等問題。本文將跟隨《Rust 程序設計語言》通過剖析迭代器的設計原理、使用方法及底層機制,幫助你掌握這一工具,并寫出更符合 Rust 哲學的代碼。

定義

迭代器模式允許你依次對一個序列中的項執行某些操作。迭代器iterator)負責遍歷序列中的每一項并確定序列何時結束的邏輯。

在 Rust 中,迭代器是 惰性的lazy),這意味著在調用消費迭代器的方法之前不會執行任何操作。

fn main() {let v1 = vec![1, 2, 3];// 創建了一個迭代器,這段代碼本身并沒有執行任何有用的操作。let v1_iter = v1.iter();
}
  • 惰性求值的優勢:避免不必要的計算開銷,例如處理無限序列或僅在需要時生成元素。
  • 實際應用場景:處理大型數據集時,惰性迭代器可以節省內存,只在需要時加載數據。
  • 顯式消費的必要性:必須調用消費方法(如collect())才能觸發實際迭代,否則不會執行任何操作。

使用for 關鍵字打印出數組中的元素。

fn main() {let v1 = vec![1, 2, 3];// 創建了一個迭代器,這段代碼本身并沒有執行任何有用的操作。let v1_iter = v1.iter();for val in v1_iter {println!("Got: {}", val);}
}

Iterator Trait 和 next方法

迭代器都實現了一個叫做 Iterator 的定義于標準庫的 trait,源碼如下:

pub trait Iterator {type Item;fn next(&mut self) -> Option<Self::Item>;// 此處省略了方法的默認實現
}

type ItemSelf::Item,它們定義了 trait 的 關聯類型。意味著實現 Iterator trait的時候必須定義一個Item,用于next 函數的返回元素的類型。

next函數

nextIterator 實現者被要求定義的唯一方法:next 方法,該方法每次返回迭代器中的一個項,封裝在 Some 中,并且當迭代完成時,返回 None

如果調用next函數,迭代器變量要聲明為可變的。在迭代器上調用 next 方法會改變迭代器內部的狀態,每次調用next函數都會消費迭代器。

#[cfg(test)]
mod tests {#[test]fn iterator_demonstration() {let v1 = vec![1, 2, 3];// 迭代器變量要聲明為可變let mut v1_iter = v1.iter();assert_eq!(v1_iter.next(), Some(&1));assert_eq!(v1_iter.next(), Some(&2));assert_eq!(v1_iter.next(), Some(&3));assert_eq!(v1_iter.next(), None);}
}

代碼中調用了四次next函數,如果有值返回的是由Some包著的引用,如果沒有值了返回None。

根據需要可以獲取不同引用所有權的迭代器:

  1. iter() 創建的是不可變引用的迭代器。
  2. into_iter() 能獲得數組的的所有權,并返回具有所有權的值。
  3. iter_mut() 創建的是一個可以遍歷到可變引用的迭代器。
方法元素類型所有權原集合后續可用性
iter()&T借用
iter_mut()&mut T可變借用
into_iter()T轉移所有權

示例:所有權發生轉移,println!不能再使用v1

let v1 = vec![1, 2, 3];
let v1_iter = v1.into_iter();
// println!("{:?}", v1); // 編譯錯誤:value borrowed after move

消費迭代器的方法

Iterator trait 有一系列不同的由標準庫提供默認實現的方法。我們可以在 Iterator trait 的標準庫 API 文檔中找到所有這些方法。一些方法在其定義中調用了 next 方法,這也就是為什么在實現 Iterator trait 時要求實現 next 方法的原因。這些調用 next 方法的方法被稱為 消費適配器consuming adaptors),因為調用它們會消耗迭代器。一個消費適配器的例子是 sum 方法。這個方法獲取迭代器的所有權并反復調用 next 來遍歷迭代器,因而會消費迭代器。在遍歷過程中,它將每個項累加到一個總和中,并在迭代完成時返回這個總和。

點開sum函數源碼,并沒看到調用next方法,這里其實是使用了 Sum traitIterator::sum() 的實現通過將遍歷和累加委托給 Sum trait,只要能確認迭代器中存放的什么類型就能由對應的trait實現求和。后續這里我專門寫一篇文章探究學習一下。

    #[stable(feature = "iter_arith", since = "1.11.0")]fn sum<S>(self) -> SwhereSelf: Sized,S: Sum<Self::Item>,{Sum::sum(self)}
  • 標準庫sum方法文檔:https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.sum

使用sum() 對集合當中的元素求和

		#[test]fn test_sum() {let v1 = vec![1,2,3];let total: i32 = v1.iter().sum();assert_eq!(total, 6);}

創建迭代器的方法

Iterator trait 中定義了另一類方法,被稱為 迭代適配器iterator adaptors),它們不會消耗當前的迭代器,而是通過改變原始迭代器的某些方面來生成不同的迭代器,如 map方法。

    #[test]fn test_map() {let v1 = vec![1,2,3];let v3: Vec<_> = v1.iter().map(|i| i + 1).collect();assert_eq!(v3, vec![2, 3, 4]);}

由于 map 接受一個閉包,因此我們可以指定希望在每個元素上執行的任何操作。這是一個很好的例子,展示了如何通過閉包來自定義某些行為,同時復用 Iterator trait 提供的迭代行為。

可以鏈式調用多個迭代器適配器來以一種可讀的方式進行復雜的操作。不過因為所有的迭代器都是惰性的,你必須調用一個消費適配器方法,才能從這些迭代器適配器的調用中獲取結果。

消費迭代器的方法叫做消費適配器

創建迭代器的方法 叫做迭代適配器

使用捕獲其環境的閉包

很多迭代器適配器接受閉包作為參數,而我們通常會指定捕獲其環境的閉包作為迭代器適配器的參數。

在這里再介紹一個迭代適配器filter(),也利用了閉包中的一個特性:通過閉包捕獲定義它的環境中的值(跳轉閉包相關文章)。

我們使用 filter 方法來獲取一個閉包。該閉包從迭代器中獲取一項并返回一個 bool。如果閉包返回 true,其值將會包含在 filter 提供的新迭代器中。如果閉包返回 false,其值不會被包含。

使用 filter 方法和一個捕獲 shoe_size 的閉包,示例代碼如下:

#[derive(PartialEq, Debug)]
struct Shoe {size:i32,style: String,
}fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: i32) -> Vec<Shoe> {// 必須使用into_iter() 獲得數組所有權,因為collect 要求生成一個Vec<Shoe>shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}
#[test]fn filters_by_size() {let shoes = vec![Shoe {size: 10,style: String::from("sneaker"),},Shoe {size: 13,style: String::from("sandal"),},Shoe {size: 10,style: String::from("boot"),},];let in_my_size = shoes_in_size(shoes, 10);assert_eq!(in_my_size,vec![Shoe {size: 10,style: String::from("sneaker")},Shoe {size: 10,style: String::from("boot")},]);}

shoes_in_size 函數獲取一個鞋子 vector 的所有權和一個鞋碼作為參數。它返回一個只包含指定鞋碼的鞋子的 vector。

shoes_in_size 函數體中調用了 into_iter 來創建一個獲取 vector 所有權的迭代器。接著調用 filter 將這個迭代器適配成一個只含有那些閉包返回 true 的元素的新迭代器。

閉包從環境中捕獲了 shoe_size 變量并使用其值與每一只鞋的大小作比較,只保留指定鞋碼的鞋子。最終,調用 collect 將迭代器適配器返回的值收集進一個 vector 并返回。

這個測試展示當調用 shoes_in_size 時,返回的只會是與我們指定的鞋碼相同的鞋子。


在代碼中使用的是into_iter(),沒有使用iter()是為什么呢? 這里再分析一下他們的區別:

iter()into_iter() 的核心區別

  • iter():生成一個 不可變引用 的迭代器,元素類型為 &T。原集合保留所有權,后續仍可使用。
  • into_iter():生成一個 擁有所有權 的迭代器,元素類型為 T。原集合被消耗(所有權轉移),后續無法再使用。

調用collect()方法 試圖將引用類型 &Shoe 收集到 Vec<Shoe> 中,但 Vec<Shoe> 只能存儲 Shoe 類型的元素,不能存儲引用,所以需要獲得所有權。使用 into_iter() 是為了將元素的所有權從原集合轉移到新集合中,確保 collect() 可以直接生成 Vec<Shoe>,避免類型不匹配和克隆開銷。這是 Rust 所有權系統和類型安全性的直接體現。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/77662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/77662.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/77662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

若依框架二次開發——RuoYi-AI 本地部署流程

文章目錄 項目環境安裝后端1. 下載項目2. 使用 IDEA 導入項目3. 配置 Maven4. 配置 Maven settings.xml5. 初始化數據庫6. 啟動 Redis7. 修改數據庫配置8. 啟動后端服務安裝管理端1. 下載管理端項目2. 安裝依賴3. 啟動管理端4. 修改管理端配置安裝用戶端1. 下載用戶端項目2. 安…

精品推薦-最新大模型MCP核心架構及最佳實踐資料合集(18份).zip

精品推薦-最新大模型MCP核心架構及最佳實踐資料合集&#xff0c;共18份。 1、2025年程序員必學技能&#xff1a;大模型MCP核心技術.pdf 2、MCP 架構設計剖析&#xff1a;從 Service Mesh 演進到 Agentic Mesh.pdf 3、MCP 架構設計深度剖析&#xff1a;使用 Spring AI MCP 四步…

DataWorks智能體Agent發布!基于MCP實現數據開發與治理自動化運行

在傳統的數據開發工作中&#xff0c;企業用戶或者開發者常常需要進行繁瑣的配置、復雜的代碼撰寫、反復的性能調優和大量重復性的操作&#xff0c;才能實現數據開發、數據集成和數據治理等工作&#xff0c;效率十分低下。 近日&#xff0c;阿里云大數據開發治理平臺DataWorks基…

IDEA 中右側沒有顯示Maven

IDEA 中右側沒有顯示Maven 1. 檢查 Maven 項目是否正確加載 現象 ? 項目是 Maven 項目&#xff0c;但右側沒有 Maven 工具窗口。 ? 項目根目錄下有 pom.xml&#xff0c;但 IDEA 沒有識別為 Maven 項目。 解決方法 手動重新加載 Maven 項目&#xff1a; ? 在 IDEA 中&…

羅技K860鍵盤

羅技藍牙鍵盤的頂部功能鍵F1-F12的原本功能 單擊羅技鍵盤的功能鍵時&#xff0c;默認響應的是鍵盤上面顯示的快進、調節音量等功能。改變回F1~F12原本功能&#xff0c;同時按下 fn和esc組合鍵

什么是大型語言模型(LLM)?哪個大模型更好用?

什么是 LLM&#xff1f; ChatGPT 是一種大型語言模型 (LLM)&#xff0c;您可能對此并不陌生。它以非凡的能力而聞名&#xff0c;已證明能夠出色地完成各種任務&#xff0c;例如通過考試、生成產品內容、解決問題&#xff0c;甚至在最少的輸入提示下編寫程序。 他們的實力現已…

css畫右上角 角標三角形

.corner {position: absolute;top: -2rem;right: -2rem;width: 0;height: 0;border: 2rem solid red;border-bottom-color: transparent;border-top-color: transparent;border-left-color: transparent;transform: rotateZ(135deg); } 基本思路就是設置border&#xff0c;只設…

vue自定義顏色選擇器

vue自定義顏色選擇器 效果圖&#xff1a; step0: 默認寫法 調用系統自帶的顏色選擇器 <input type"color">step1:C:\Users\wangrusheng\PycharmProjects\untitled18\src\views\Home.vue <template><div class"container"><!-- 顏…

[Python] 企業內部應用接入釘釘登錄,端內免登錄+瀏覽器授權登錄

[Python] 為企業網站應用接入釘釘鑒權&#xff0c;實現釘釘客戶端內自動免登授權&#xff0c;瀏覽器中手動釘釘授權登錄兩種邏輯。 操作步驟 企業內部獲得 開發者權限&#xff0c;沒有的話先申請。 訪問 釘釘開放平臺-應用開發 創建一個 企業內部應用-釘釘應用。 打開應用…

[藍橋杯 2023 國 Python A] 整數變換

P10985 [藍橋杯 2023 國 Python A] 整數變換 題目背景 建議使用 PyPy3 提交本題。 題目描述 小藍有一個整數 n n n。每分鐘&#xff0c;小藍的數都會發生變化&#xff0c;變為上一分鐘的數 減去上一分鐘的數的各個數位和。 例如&#xff0c;如果小藍開始時的數為 23 23 …

【Linux】TCP_Wrappers+iptables實現堡壘機功能

規劃 顯示jumpserver的簡單功能&#xff0c;大致的網絡拓撲圖如下 功能規劃 & 拓撲結構 JumpServer&#xff08;堡壘機&#xff09;主要功能&#xff1a; 對訪問目標服務器進行統一入口控制&#xff08;例如 nginx、mysql、redis&#xff09;。使用 iptables 做 NAT 轉…

用HTML和CSS繪制佩奇:我不是佩奇

在這篇博客中&#xff0c;我將解析一個完全使用HTML和CSS繪制的佩奇(Pig)形象。這個項目展示了CSS的強大能力&#xff0c;僅用樣式就能創造出復雜的圖形&#xff0c;而不需要任何圖片或JavaScript。 項目概述 這個名為"我不是佩奇"的項目是一個純CSS繪制的卡通豬形象…

Spring 中 WebFlux 編寫一個簡單的 Controller

引言&#xff1a;響應式編程與 WebFlux 隨著應用程序需要處理大量并發請求的情況越來越多&#xff0c;傳統的 Servlet 編程模式可能無法滿足高效和低延遲的需求。為了應對這種情況&#xff0c;Spring 5 引入了 WebFlux&#xff0c;一個基于響應式編程的 Web 框架&#xff0c;旨…

React十案例下

代碼下載 登錄模塊 用戶登錄 頁面結構 新建 Login 組件&#xff0c;對應結構: export default function Login() {return (<div className{styles.root}><NavHeader className{styles.header}>賬號登錄</NavHeader><form className{styles.form}>&…

100道C#高頻經典面試題帶解析答案——全面C#知識點總結

100道C#高頻經典面試題帶解析答案 以下是100道C#高頻經典面試題及其詳細解析&#xff0c;涵蓋基礎語法、面向對象編程、集合、異步編程、LINQ等多個方面&#xff0c;旨在幫助初學者和有經驗的開發者全面準備C#相關面試。 &#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、CSD…

機動車號牌管理系統設計與實現(代碼+數據庫+LW)

摘 要 在如今社會上&#xff0c;關于信息上面的處理&#xff0c;沒有任何一個企業或者個人會忽視&#xff0c;如何讓信息急速傳遞&#xff0c;并且歸檔儲存查詢&#xff0c;采用之前的紙張記錄模式已經不符合當前使用要求了。所以&#xff0c;對機動車號牌信息管理的提升&…

VMWare Workstation Pro17.6最新版虛擬機詳細安裝教程(附安裝包教程)

目錄 前言 一、VMWare虛擬機下載 二、VMWare虛擬機安裝 三、運行虛擬機 前言 VMware 是全球領先的虛擬化技術與云計算解決方案提供商&#xff0c;通過軟件模擬計算機硬件環境&#xff0c;允許用戶在一臺物理設備上運行多個獨立的虛擬操作系統或應用。其核心技術可提升硬件…

DeepSeek的神經元革命:穿透搜索引擎算法的下一代內容基建

DeepSeek的神經元革命&#xff1a;穿透搜索引擎算法的下一代內容基建 ——從語義網絡到價值共識的范式重構 一、搜索引擎的“內容饑渴癥”與AI的基建使命 2024年Q1數據顯示&#xff0c;百度索引網頁總數突破3500億&#xff0c;但用戶點擊集中在0.78%的高價值頁面。這種“數據…

docker安裝nginx,基礎命令,目錄結構,配置文件結構

Nginx簡介 Nginx是一款輕量級的Web服務器(動靜分離)/反向代理服務器及電子郵件&#xff08;IMAP/POP3&#xff09;代理服務器。其特點是占有內存少&#xff0c;并發能力強. &#x1f517;官網 docker安裝Nginx &#x1f433; 一、前提條件 ? 已安裝 Docker&#xff08;dock…

Python Lambda表達式詳解

Python Lambda表達式詳解 1. Lambda是什么&#xff1f; Lambda是Python中用于創建匿名函數&#xff08;沒有名字的函數&#xff09;的關鍵字&#xff0c;核心特點是簡潔。它適用于需要臨時定義簡單函數的場景&#xff0c;或直接作為參數傳遞給高階函數&#xff08;如map()、f…