用Iterator解釋Rust所有權概念
當涉及到集合中元素的所有權時,迭代器起著極其重要的作用。
在下面這些例子中,我們將使用Vec<String>,故意使用String作為元素(它沒有實現Copy trait:String預設是值傳遞,不是引用傳遞,也不是值複製),這樣我們就可以在向量中演示其移動語義。
讓我們從一個對names進行迭代的for-loop開始。為什麼是for-loop?我們後面將討論這個問題。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in names { println!("{}", name); } } |
但是,當直到我們在for-loop下面新增一個print語句......在那裡編譯器開始抱怨。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in names { println!("{}", name); } println!("Names: {:?}", names); } |
編譯器:
error[E0382]: borrow of moved value: `names` --> src/main.rs:11:29 |
顯然,在迴圈之前有一個 "隱含的.into_iter呼叫"。
等等,隱式?為什麼呢!?但是,好吧,讓我們新增那個隱式的.into_iter。
在加入into_iter()之後,我們預計程式仍然不能編譯。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in names.into_iter() { println!("{}", name); } println!("Names: {:?}", names); } |
error[E0382]: borrow of moved value: `names` --> src/main.rs:11:29 |
嗯,讓我們給names.into_iter()分配一個變數。這樣我們就可以直觀地看到這個動作。請注意,我們仍然希望程式不被編譯。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let names_iter = names.into_iter(); for name in names_iter { println!("{}", name); } println!("Names: {:?}", names); } |
error[E0382]: borrow of moved value: `names` --> src/main.rs:11:29 |
發生的情況是,使用 into_iter,我們正在將元素從 names 移到 names_iter。結果是,我們不能再使用names了!
我們該怎麼做呢?
我們可以使用.iter()從名字中借用元素:
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in names.iter() { println!("{}", name); } println!("Names: {:?}", names); } |
正常輸出:
John Jane Names: ["John", "Jane"] |
我們可以使用一個slice(實現了IntoIterator):
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in &names { println!("{}", name); } println!("Names: {:?}", names); } |
正常輸出
如果你的程式允許,我們可以把程式碼行調換一下,先借用名字,然後再移動它。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; println!("Names: {:?}", names); for name in names { println!("{}", name); } } |
我們也可以克隆該vector。請注意,克隆是有成本的。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; for name in names.clone() { println!("{}", name); } println!("Names: {:?}", names); } |
函數語言程式設計
使用函數語言程式設計成語使得當你想對元素進行迭代時,迭代器的作用更加明顯(尤其是當你來自於不用直接處理迭代器的程式語言時)。
與for-loop不同,沒有隱含的.into_iter()呼叫。因此,對於向量,我們總是需要呼叫.iter()、.into_iter()等來獲得一個迭代器。
下面程式碼不能編譯,因為我們需要對元素進行迭代,這意味著我們需要使用例如.iter()獲得一個迭代器。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; names.for_each(|name| println!("{}", name)); println!("{:?}", names); } |
error[E0599]: `Vec<String>` is not an iterator --> src/main.rs:7:11 |
這裡,我們使用了.iter()和.for_each()的組合。
迭代器返回一個元素的引用。我們仍然可以在之後使用names物件。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; names .iter() .for_each(|name| println!("{}", name)); println!("{:?}", names); } |
輸出:
John Jane <p class="indent">["John", "Jane"] |
如果你想移動這些元素,可以使用.into_iter()。然而,請注意,之後我們就不能使用這個向量了。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; names .into_iter() .for_each(|name| println!("{}", name)); println!("{:?}", names); } |
error[E0382]: borrow of moved value: `names` --> src/main.rs:12:22 |
你需要重新設計你的程式,使你不使用被移動的元素。這裡,我們把列印語句移到了前面。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; println!("{:?}", names); names .into_iter() .for_each(|name| println!("{}", name)); } |
我們也可以在呼叫.into_iter()之前克隆該向量。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; names.clone() .into_iter() .for_each(|name| println!("{}", name)); println!("{:?}", names); } |
相關文章
- 通俗易懂解釋Rust所有權和借用概念Rust
- 使用共享引用說明Rust所有權概念Rust
- Rust所有權__OwnershipRust
- Rust 所有權如何理解Rust
- Rust所有權及引用Rust
- Rust 所有權和借用Rust
- RUST所有權相關問題Rust
- rust學習五、認識所有權Rust
- Rust 程式設計影片教程對應講解內容-所有權Rust程式設計
- Rust 程式設計視訊教程對應講解內容-所有權Rust程式設計
- 「Kafka應用」名詞概念解釋Kafka
- rust-quiz:026-iterator-lazy-map.rsRustUI
- Rust記憶體安全解釋Rust記憶體
- 分散式快取 - 概念解釋分散式快取
- 【Rust學習】記憶體安全探秘:變數的所有權、引用與借用Rust記憶體變數
- 用幾條規則解釋關於js原型的所有問題JS原型
- 鮑勃大爺:SOLID概念解釋Solid
- 【generatory與iterator】的應用
- 前端非同步的解釋-概念性前端非同步
- 微服務 - 概念 · 應用 · 通訊 · 授權 · 跨域 · 限流微服務跨域
- PHP遍歷介面Iterator詳解PHP
- Rust 1.79.0釋出Rust
- Rust 1.59.0釋出Rust
- Rust 1.60.0釋出Rust
- 可變所有權型別型別
- 介面的所有權之爭
- 谷歌大腦提出概念啟用向量,助力神經網路可解釋性研究谷歌神經網路
- 領域驅動設計的概念解釋 -DEVdev
- JEE、J2EE與Jakarta等概念解釋
- Rust 1.83.0 版本釋出Rust
- Rust 註釋介紹Rust
- 一圖看懂所有機器學習概念機器學習
- 一文帶你看清 HTTP 所有概念HTTP
- oracle goldengate實用文件兩個(所有命令幫助及ogg錯誤程式碼解釋)OracleGo
- rust實戰系列 - 使用Iterator 迭代器實現斐波那契數列(Fibonacci )Rust
- Iterator & foreach
- Rust 註釋生成文件Rust
- MySql給賬戶所有許可權MySql