1. 程式人生 > >rust 迭代器 (iterator) 詳解

rust 迭代器 (iterator) 詳解

翻譯來源

這篇文章的目的是為一些常見的iterator提供參考資料。並不能替代Iterator
API
或者書中的Rust iterator核心概念 ,事實上這篇文章的內容來自以上兩種內容。

為了更好理解本篇文章內容,推薦讀者至少粗略瞭解Rust

如何編譯執行例子

git clone https://github.com/rustomax/rust-iterators.git
cd rust-iterators/
cargo run

程式碼中使用了nightly版本的特性,如果你的Rust 為statble版本,請註釋相應的程式碼區域。

0介紹

生活是重複的,其中的大部分事物都是成系列的。我們經常需要記錄(count)、列舉
(enumerate)、反覆申明(iterate)這些事物。在程式設計中,有多種方式產生重複事物(repetition),其中最為人熟知的是C風格的for迴圈。

for ( x = 0; x < 10; ++x ) {
  // do something
}

雖然這種可行的方法足夠強大而且足夠靈活以適應多種情況,但它承擔著對應的bug份額,例如錯誤分號放置、無意中在迴圈內部修改變數。本著與其他語言特性的安全和一致的精神,Rust中沒有C風格的迴圈。 相反,Rust利用迭代器實現類似的目標(還有更多)。

1.基本Range

在Rust中迴圈一系列整數的最基本的方法是Range。Range由..標記產生,它生成步長為1的iterator 。

for i in 1..11 {
    print!("{} ", i);
}
// output: 1 2 3 4 5 6 7 8 9 10

上面的程式碼將列印從1到10的一系列數字,而不包括最後一個數字11.換句話說,..會產生一個iterator ,它包含左邊的數,排除在右邊的數。 為了得到一個包含兩端的範圍的iterator,你使用...符號。 包含兩端的範圍的iterator目前是一個不穩定的功能,需要nightly編譯器

#![feature(inclusive_range_syntax)]

for i in 1...10 {
  print!("{} ", i);
}
// output: 1 2 3 4 5 6 7 8 9 10

如果你不使用迴圈迭代器變數,你可以通過利用_來避免例項化它。 例如,下面的程式碼不需要例項化一個迴圈迭代器變數就可以輸出迭代器中元素的數量:

let mut n: i32 = 0;
for _ in 0..10 {
  n += 1;
}
println!("num = {}", n);
// output: num = 10

上面的例子是有些多餘,因為Rust中的迭代器有count()函式,它返回迭代器中元素的數量,而不需要在迴圈中對它們進行計數:

println!("num = {}", (0..10).count());
// output: num = 10

你會發現有經驗的Rust程式設計師能夠用非常簡潔的迭代器語言來表達,而不是採用的傳統迴圈程式碼行。 當我們談論介面卡(adaptor),消費者(consumer)和將迭代器方法連結(chaining)到複雜的語句時,我們將覆蓋下面的一些模式。

2.深層發掘(Digging Deeper)

如果基本的增量順序Range 不能滿足你的需要,Rust中有很多方法來定製Range迭代器。 我們來看幾個常見的問題。

通常,Range遞增不是1,而是增加一個不同的數字。 這可以通過filter()方法來實現。 它應用一個閉包(closure),它可以為迭代器的每個元素返回true或false,併產生一個只包含閉包返回true的元素的迭代器。

下面的迭代器將產生一個0到20之間的偶數序列。

for i in (0..21).filter(|x| (x % 2 == 0)) {
  print!("{} ", i);
}
// output: 0 2 4 6 8 10 12 14 16 18 20

因為filter()使用閉包,所以非常靈活,可以用來生成複雜迭代器。 例如,下面的迭代器產生0到20之間的一系列整數,它們除以2和3得到餘數:

for i in (0..21).filter(|x| (x % 2 == 0) && (x % 3 == 0)) {
  print!("{} ", i);
}
// output: 0 6 12 18

雖然預設範圍是遞增的,但是使用rev()方法可以很容易地將其反轉。

for i in (0..11).rev() {
  print!("{} ", i);
}
// output: 10 9 8 7 6 5 4 3 2 1 0

另一個常見的迭代器介面卡map()將閉包應用於每個元素,並返回結果迭代器。下面是一個迭代器的例子,它產生一個從1到10的數字的正方形序列:

for i in (1..11).map(|x| x * x) {
    print!("{} ", i);
}
// output: 1 4 9 16 25 36 49 64 81 100

fold()是一個非常強大的方法。 它返回一個特殊的“累加器”型別閉包的結果給迭代器的所有元素,得到一個單一的值。 下面的迭代器產生從1到5的數字的平方和。

#![feature(inclusive_range_syntax)]

let result = (1...5).fold(0, |acc, x| acc + x * x);
println!("result = {}", result);

// output: result = 55

也許理解這裡發生的最簡單的方法是以更程式化的方式重寫上面的例子:

#![feature(inclusive_range_syntax)]

let mut acc = 0;

for x in 1...5 {
  acc += x * x;
}

let result = acc;
println!("result = {}", result);

// output: result = 55

哇!fold()版本是不是更加簡潔和可讀?

3.陣列迭代(Iterating over Arrays)

與迭代Range類似,我們可以迭代一個數組。 這樣做的好處是陣列可以包含任意型別的值,而不僅僅是整數。 唯一的警告是該陣列不是一個迭代器。 我們需要使用iter()方法把它變成一個迭代器。

let cities = ["Toronto", "New York", "Melbourne"];

for city in cities.iter() {
  print!("{}, ", city);
}
// output: Toronto, New York, Melbourne,

4.組合迭代器介面卡(Combining Iterator Adaptors)

在前面的章節中,我們介紹了各種各樣的方法,可以讓你生成許多不同型別的迭代器,當你開始結合這些方法的時候,Rust表現十分突出。

如果你想要一個100之間以步長2Range呢? 通過將一個特性和幾個方法組合到一個迭代器中可以很容易地完成這個任務:

#![feature(inclusive_range_syntax)]

for i in (0...10).rev().filter(|x| (x % 2 == 0)) {
  print!("{} ", i);
}
// output: 10 8 6 4 2 0

需要一個不連續的Range(基本上是兩個不相Range的組合)? 您可以使用chain()方法組合多個範圍:

let c = (1..4).chain(6..9);

for i in c {
  print!("{} ", i);
}
// output: 1 2 3 6 7 8

你可以得到很有創意的組合的東西! 下面是一個迭代器,結合了兩個範圍:第一個遞增和過濾,另一個 是遞減。 不知道這樣一個可憎的東西怎麼產生,但在這裡卻是實現!

let r = (1..20)
  .filter(|&x| x % 5 == 0)
  .chain((6..9).rev());

for i in r {
  print!("{} ", i);
}
// output: 5 10 15 8 7 6

請注意,在上面的例子中,Rust允許我們通過將複雜的迭代器語句拆分為多行來更好地表示覆雜的迭代器語句。

另一個方便的方法是zip()。 它有點類似於chain(),因為它將兩個迭代器合併為一個。 與chain()相比,zip()不產生連續的迭代器,而是產生元組(tuple)的迭代器:
這裡寫圖片描述

let cities = ["Toronto", "New York", "Melbourne"];
let populations = [2_615_060, 8_550_405, ‎4_529_500];

let matrix = cities.iter().zip(populations.iter());

for (c, p) in matrix {
  println!("{:10}: population = {}", c, p);
}
// output:
// Toronto   : population = 2615060
// New York  : population = 8550405
// Melbourne : population = 4529500

5.字元Range(Ranges of Characters)

操作字串或文字的位元組數通常需要迭代字元Range的能力。 char_iter提供了方便的方法來產生這樣的範圍。 char_iter支援Unicode字元。

要使用char_iter,請在Cargo.toml中新增以下內容

[dependencies]
char-iter = "0.1"

接著通過char_iter::new()產生字元Range

extern crate char_iter;

for c in char_iter::new('Д', 'П') {
  print!("{} ", c);
}
// output: Д Е Ж З И Й К Л М Н О П

6.向量迭代(Iterating over Vectors)

向量是Rust的基本結構之一。 就其性質而言,它非常適合於表示一系列重複專案。 Rust中有許多語言工具允許使用向量作為迭代器,反之亦然。

在最簡單的情況下,類似於我們如何從陣列建立迭代器,我們可以使用iter()方法從向量建立迭代器。 事實上,這被認為是Rust在迭代向量中最習慣的方式。

let nums = vec![1, 2, 3, 4, 5];

for i in nums.iter() {
   print!("{} ", i);
}
// output: 1 2 3 4 5

事實上,上面的模式非常普遍,Rust的引用操作符為其提供了句法糖。

let nums = vec![1, 2, 3, 4, 5];
for i in &nums {
   print!("{} ", i);
}
// output: 1 2 3 4 5

注意上面的借用(borrow)是不可改變的。 換句話說,它們是隻讀的。 如果我們想要改變我們的向量,我們必須使用可變的借用&mut。 例如,下面的程式碼將可變地迭代一個向量,使處理中的每個元素加倍。

let mut nums = vec![1, 2, 3, 4, 5];
for i in &mut nums {
    *i *= 2;
}
println!("{:?}", nums);

//output: [2, 4, 6, 8, 10]

然而,現在你是一個迭代忍者(),你不會使用上面的for迴圈語法。 你會用一個地map()來代替,對嗎?

let nums = vec![1, 2, 3, 4, 5];
let nums = nums.iter().map(|x| x * 2);
println!("{:?}", nums);

//output: [2, 4, 6, 8, 10]

輕微的離題。 如果我們想要使用可變的迭代器將元素新增到向量中,如下所示:

let mut nums = vec![1, 2, 3, 4, 5];
for i in &mut nums {
    nums.push(*i);
}
println!("{:?}", nums);

它不編譯,並丟擲錯誤資訊cannot borrow `nums` as mutable more than once at a time。 你看,我們的迭代器(在for迴圈中例項化)已經借用nums作為可變。 push表達試圖再次這樣做,這是禁止的。 這是在Rust中著名的安全機制。 如果我們可以將某個push入向量中,同時迭代它,則會導致迭代器失效,從而導致未定義的行為。 Rust可以在編譯時防止發生這種情況。 迭代器不僅強大,而且它們也是超級安全的。

現在,我們做相反的事情 : 從迭代器建立一個向量。 為了做到這一點,我們需要所謂的消費者。 消費者迫使懶惰的迭代器實際產生值。collect()是一個普通的消費者。 它從一個迭代器獲取值並將它們轉換為所需型別的集合。 下面我們將從110的一系列數字變換成一個向量i32

let v = (1..11).collect::<Vec<i32>>();
println!("{:?}", v);
// output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

為了獲得向量的元素及其索引,可以使用enumerate()方法,該方法在每次迭代中返回一個包含索引和專案的元組:

let v = vec![1, 2, 3];
for (i, n) in v.iter().enumerate() {
    println!("v[{}] = {}", i, n);
}
// output:
// v[0] = 1
// v[1] = 2
// v[2] = 3

還有一些其他的功能,使向量上的迭代器特別有用。
min()max(),例如返回Option,分別包含向量元素的最小值和最大值:

let v = vec![3, 5, 0, -2, 3, 4, 1];
let max = v.iter().max();
let min = v.iter().min();

println!("max = {:?}, min = {:?}", max, min);

// output: max = Some(5), min = Some(-2)

sum()返回迭代器中所有值的總和。 以下程式利用sum()方法來計算一個相當平庸的學生的平均成績:

let grades = vec![4, 5, 6, 9, 7, 4, 8];
let sum: i32 = grades.iter().sum();
let gpa = sum as f32 / grades.len() as f32;

println!("sum = {}, gpa = {:.2}", sum, gpa);

// output: sum = 43, gpa = 6.14

7.無限與超越(Infinity and Beyond)

到目前為止,我們已經處理了在某些有限範圍的值上執行的迭代器。 Rust以這種方式推廣迭代器,實際上可以建立一個無限範圍! 讓我們考慮下面的例子:

let r = (1..).collect::<Vec<i32>>();

(1..)定義了一個從1開始並且無限增量的Range。 實際上,這樣的程式編譯和執行,但最終崩潰的錯誤訊息:fatal runtime error: out of memory。 那麼,你可能會說這不是很實際。 事實上,無限範圍本身是無用的。 讓他們有用的是將他們與其他介面卡和消費者結合起來。

一個特別有用的模式涉及使用take()方法來限制迭代器返回的專案數量。 下面的迭代器將返回可以被5整除的整數的正方形序列中的前10個。

let v = (1..)
  .map(|x| x * x)
  .filter(|x| x % 5 == 0 )
  .take(10)
  .collect::<Vec<i32>>();

println!("{:?} ", v);

// output: [25, 100, 225, 400, 625, 900, 1225, 1600, 2025, 2500]

8.Itertools

itertools包含強大的附加迭代器介面卡。 以下是一些例子。

為了使用itertools,需要在Cargo.toml加入如下配置:

[dependencies]
itertools = "0.6"

請回憶我們如何使用filter()生成一個偶數範圍? Itertools有一個方便的step()方法。

extern crate itertools;
use itertools::Itertools;

for i in (0..11).step(2) {
    print!("{} ", i);
}

//output: 0 2 4 6 8 10

unique()介面卡消除了迭代器的重複。 重複項不需要順序。

extern crate itertools;
use itertools::Itertools;

let data = vec![1, 4, 3, 1, 4, 2, 5];
let unique = data.iter().unique();

for d in unique {
  print!("{} ", d);
}

//output: 1 4 3 2 5

join()介面卡將迭代器元素組合為單個字串,元素之間有一個分隔符。

extern crate itertools;
use itertools::Itertools;

let creatures = vec!["banshee", "basilisk", "centaur"];
let list = creatures.iter().join(", ");
println!("In the enchanted forest, we found {}.", list);

// output: In the enchanted forest, we found banshee, basilisk, centaur.

sorted_by()介面卡將自定義排序順序應用於迭代器元素,返回排序後的向量。 根據2016年“世界幸福指數”,以下計劃將打印出前5名最幸福的國家。

extern crate itertools;
use itertools::Itertools;

let happiness_index = vec![ ("Austria", 12), ("Costa Rica", 14), ("Norway", 4),
  ("Australia", 9), ("Netherlands", 7), ("New Zealand", 8), ("United States", 13),
  ("Israel", 11), ("Denmark", 1), ("Finland", 5), ("Iceland", 3),
  ("Sweden", 10), ("Canada", 6), ("Puerto Rico", 15), ("Switzerland", 2) ];

let top_contries = happiness_index
  .into_iter()
  .sorted_by(|a, b| (&a.1).cmp(&b.1))
  .into_iter()
  .take(5);

for (country, rating) in top_contries {
  println!("# {}: {}", rating, country);
}

// output:
// # 1: Denmark
// # 2: Switzerland
// # 3: Iceland
// # 4: Norway
// # 5: Finland

9.定製迭代器(Creating Your Own Iterators)

Rust的優點在於,你可以使用通用語言工具來擴充套件它。 讓我們利用這個強大的力量,創造我們自己的迭代器! 我們將構建一個非常簡單的迭代器,產生一系列由浮點數(f32,f32)組成的溫度(華氏,攝氏)對。 溫度使用公知的公式計算:°C =(°F-32)/ 1.8

迭代器以一個結構體(struct)開始。 我們命名的結構體名稱也將是迭代器的名稱。 我們將呼叫FahrToCelc。 該結構體包含一些有用的資訊,這些資訊在隨後的迭代器呼叫之間保持不變。 我們將有兩個 f32 fields : 華氏溫度和增量步長:

struct FahrToCelc {
  fahr: f32,
  step: f32,
}

接下來,我們將建立一個的方法new(),它通過初始化迭代器的初始值以華氏溫度和增量步長進行初始化。 這個方法嚴格來說不是必須的,不是迭代器實現的一部分,但是我覺得它是一個很好的語法糖,可以提高程式的整體可讀性:

impl FahrToCelc {
  fn new(fahr: f32, step: f32) -> FahrToCelc {
    FahrToCelc { fahr: fahr, step: step }
  }
}

最後,我們通過為結構實現Iterator Trait來編寫迭代器的行為。 至少需要包含以下內容:

  • 定義Item型別。 它描述了迭代器將產生什麼樣的東西。 如前所述,我們的迭代器產生由浮點數(f32,f32)元組表示的溫度對(華氏,攝氏),所以我們的Item型別定義如下所示:
 type Item = (f32, f32);
  • 函式next()實際上會生成下一個Itemnext()self進行可變引用( mutable reference),並返回一個封裝下一個值的Option。 我們必須返回一個選項而不是專案本身的原因是因為許多迭代器需要考慮它們已經達到序列結束的情況,在這種情況下它們返回None。 由於我們的迭代器生成一個無限序列,我們的next()方法將始終返回Option <Self :: Item>。 因此,我們的next()函式宣告如下所示:
fn next (&mut self) -> Option<Self::Item>

next()函式通常也會進行一些內部管理。 我們逐步增加華氏溫度fahr,以便在隨後的迭代中返回。 對內部欄位進行這些修改是我們需要將self的可變引用傳遞給next()作為引數的原因。
結合在一起,這裡是迭代器特徵的實現:

impl Iterator for FahrToCelc {
  type Item = (f32, f32);

  fn next (&mut self) -> Option<Self::Item> {
    let curr_fahr = self.fahr;
    let curr_celc = (self.fahr - 32.0) / 1.8;
    self.fahr = self.fahr + self.step;
    Some((curr_fahr, curr_celc))
  }
}

最終的完整程式如下:

struct FahrToCelc {
  fahr: f32,
  step: f32,
}

impl FahrToCelc {
  fn new(fahr: f32, step: f32) -> FahrToCelc {
    FahrToCelc { fahr: fahr, step: step }
  }
}

impl Iterator for FahrToCelc {
  type Item = (f32, f32);

  fn next (&mut self) -> Option<Self::Item> {
    let curr_fahr = self.fahr;
    let curr_celc = (self.fahr - 32.0) / 1.8;
    self.fahr = self.fahr + self.step;
    Some((curr_fahr, curr_celc))
  }
}

fn main() {
  // pass the starting temperature and step to the initializer function
  let ftc = FahrToCelc::new(0.0, 5.0);

  // produce the iterator table of first 5 values
  let temp_table = ftc.take(5);

  // print out the temperature table nicely
  for (f, c) in temp_table {
    println!("{:7.2} °F = {:7.2} °C", f, c);
  }
}

// output:
//  0.00 °F =  -17.78 °C
//  5.00 °F =  -15.00 °C
// 10.00 °F =  -12.22 °C
// 15.00 °F =   -9.44 °C
// 20.00 °F =   -6.67 °C

相關推薦

rust (iterator)

翻譯來源 這篇文章的目的是為一些常見的iterator提供參考資料。並不能替代Iterator API或者書中的Rust iterator核心概念 ,事實上這篇文章的內容來自以上兩種內容。 為了更好理解本篇文章內容,推薦讀者至少粗略瞭解Rust

c++Iterator

1 C++ Iterators(迭代器) 迭代器可被用來訪問一個容器類的所包函的全部元素,其行為像一個指標。 舉一個例子,你可用一個迭代器來實現對vector容器中所含元素的遍歷。有這麼幾種迭代器如下: 迭代器 描述 input_iterator   提供讀功能的向前移動迭

C++標準模板庫 iterator (一)

[cpp] view plaincopyprint? #include <vector> #include <iostream> #include <list> #include <

Java(iterator以及和for迴圈的區別)

前言:        迭代器是一種模式、詳細可見其設計模式,可以使得序列型別的資料結構的遍歷行為與被遍歷的物件分離,即我們無需關心該序列的底層結構是什麼樣子的。只要拿到這個物件,使用迭代器就可以遍歷這個物件的內部。Iterable:實現這個介面的集合物件支援迭代,是可以迭代的

什麼是,舉例

2018年11月05日 20:30:11 HZY199321 閱讀數:5 個人分類: 個人成長

C++ STL使用

寫在前面,迭代器這種東西,就是為了使訪問簡單!! 容器::iterator iter; for(iter= 容器.begin();iter!=容器.end();iter++){ cout<<*iter或者是 iter->first等等之類的    

opencv學習-使用iterator遍歷

1.Mat Iterator_是一個模板類 2.一個影象迭代器使用如下方式宣告: Mat Iterator_ it;或Mat_::iterator it;【推薦使用】 3.使用常規的begin和end來遍歷所有畫素。 4.模板函式begin,end 5.Mat

Python中的生成器(generator)和(Iterator)

Python是一種動態的程式語言,那就具有動態程式語言的特性,可以在執行時改變其結構,比如新的函式,物件、程式碼也可以引進,已有的函式可以被刪除。。。目前最常用的可以歸納為以下幾點:1.執行的過程中給物件繫結(新增)屬性,2.執行過程中給類繫結(新增)屬性,3.執行的過程中給類繫結(新增)方法,4.

PythonIterator和生成器generator

容器(container) 容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,可以用in, not in關鍵字判斷元素是否包含在容器中。通常這類資料結構把所有的元素儲存在記憶體中(也有一些特例,並不是所有的元素都放在記憶體,比如迭代器和生成器物件) 可迭代物

python 入門第三課 物件Iterable和Iterator

迭代物件Iterable和迭代器Iterator __author__ = 'admin' from collections.abc import Iterator from collections.abc import Iterable print(isinstance([],Iterable)) p

《OpenCV3程式設計入門》——5.1.5 訪問影象中畫素的三類方法(指標訪問、iterator、動態地址計算配合at元素)

目錄 1、指標訪問畫素 2、迭代器操作畫素 3、動態地址計算 OpenCV中,有三種方式訪問影象畫素:  指標訪問:C操作符[]; 迭代器iterator 動態地址計算 上述方法在訪問速度上略有差異。debug模式下,

JAVA自查:Iterator

迭代(來自百度) 通俗點說 叫 一個個數過去, 實現這樣一個個數過去功能的東西,叫迭代器。 java迭代器 較多使用在容器中,如陣列連結串列 ArrayList(反正就是能裝東西的玩意兒) 舉個例子: //我們先往連結串列中裝東西 ArrayList a = new ArrayList();

反向reverse_iterator與正向iterator之間的轉換(以及例項應用)

反向迭代器     相信大家對正向迭代器應該都很熟悉,然而對於反向迭代器的使用確是有幾處需要注意的地方,在此記錄一下。先看STL原始碼處註釋如下: /** * Bidirectional and random access iterators have c

java集合中的:Iterator

集合的迭代器:iterator 迭代:在Java中”迭代”這個詞語等同於”迴圈”,”遍歷” 在集合中的”迭代”主要用來遍歷集合中的元素,把List集合和Set集合和Map集合這三種集合都轉成集合的”迭代” 集合的迭代器的本質就是把所有集合的遍歷方式轉換成迭代器這一種遍歷方式 實現步

設計模式——(Iterator)模式

  概述   迭代器模式簡單的說(按我目前的理解)就是一個類提供一個對外迭代的介面,方面呼叫者迭代。這個迭代介面至少包括兩個方法:hasNext()--用於判斷是否還有下一個,next()--用於取出下一個物件(或值)。而外部使用這個類(取出這個類中的物件或值)時,不用關心這個類儲存物

(Iterator) 和 生成器 (Generator) (八)

迭代器與生成器這一章節還沒有看的恨透,只把這一章節的例子全看完了,也看懂了。但是自己寫不出這樣優秀的程式碼。這是我缺少的技能。 // 迭代器(Iterator) 和 生成器(Generator)                  // 迭代器是一種特殊物件         

Iterator和ListIterator

Iterator迭代器 屬於設計模式,提供了一個方法,對集合/容器內的元素進行遍歷,而不用關注底層實現細節,達到資料與上層遍歷解耦的目的.(解耦: 訪問邏輯從不同型別的集合類中抽取出來,接觸兩者間的聯合關係。) Iterator迭代器提供的三種方法:(迭代器直接操作

iterator

  迭代器是一種檢查容器內元素並遍歷元素的資料型別。C++更趨向於使用迭代器而不是下標操作,因為標準庫為每一種標準容器(如vector)定義了一種迭代器型別,而只用少數容器(如vector)支援下標操作訪問容器元素。 作用類似指標 一.定義和初始化   每種容器

Scala 陣列(Array),列表(List),元組(Tuple),集(Set),對映(Map),(Iterator)

1. 陣列(Array) 陣列是程式設計中經常用到的資料結構,一般包括定長陣列和變長陣列。本教程旨在快速掌握最基礎和常用的知識,因此,只介紹定長陣列。 定長陣列,就是長度不變的陣列,在Scala中使用Array進行宣告,如下: val intValue

Java集合 Iterator分析

Iterator是個介面,是對 collection 進行迭代的迭代器,用來遍歷collection元素。但為什麼Iterator要定義成一個介面,而非一個類呢?另外,Iterator又是如何實現對collection的遍歷的呢?在對此分析之前,先看下Itera