<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                讓我們討論一下循環。 還記得Rust的`for`循環嗎?這是一個例子: ~~~ for x in 0..10 { println!("{}", x); } ~~~ 現在我們更加了解Rust了,我們可以談談這里的具體細節了。這個范圍(`0..10`)是“迭代器”。我們可以重復調用迭代器的`.next()`方法,然后它會給我們一個數據序列。 就像這樣: ~~~ let mut range = 0..10; loop { match range.next() { Some(x) => { println!("{}", x); }, None => { break } } } ~~~ 我們創建了一個`range`的可變綁定,它是我們的迭代器。我們接著`loop`,它包含一個`match`。`match`用來匹配`range.next()`的結果,它給我們迭代器的下一個值。`next`返回一個`Option`,在這個例子中,它會返回`Some(i32)`如果有值然后返回`None`當我們循環完畢。如果我們得到`Some(i32)`,我們打印它,如果我們得到`None`,我們`break`出循環。 這個代碼例子基本上和我們的`loop`版本一樣。`for`只是`loop/match/break`結構的簡便寫法。 然而,`for`循環并不是唯一使用迭代器的結構。編寫你自己的迭代器涉及到實現`Iterator`特性。然而特性不是本章教程的涉及范圍,不過Rust提供了一系列的有用的迭代器幫助我們完成各種任務。在我們開始講解之前,我們需要看看一個Rust的反面模式。這就是如此使用范圍。 是的,我們剛剛談論到范圍是多么的酷。不過范圍也是非常原始的。例如,如果你想迭代一個向量的內容,你可能嘗試這么寫: ~~~ let nums = vec![1, 2, 3]; for i in 0..nums.len() { println!("{}", nums[i]); } ~~~ 這嚴格的說比使用現成的迭代器還要糟。你可以直接在向量上迭代。所以這么寫: ~~~ let nums = vec![1, 2, 3]; for num in &nums { println!("{}", num); } ~~~ 這么寫有兩個原因。第一,它更明確的表明了我們的意圖。我們迭代整個向量,而不是先迭代向量的索引,再按索引迭代向量。第二,這個版本也更有效率:第一個版本會進行額外的邊界檢查因為它使用了索引,`nums[i]`。因為我們利用迭代器獲取每個向量元素的引用,第二個例子中并沒有邊界檢查。這在迭代器中非常常見:我們可以忽略不必要的邊界檢查,不過仍然知道我們是安全的。 這里還有一個細節不是100%清楚的就是`println!`是如何工作的。`num`是`&i32`類型。也就是說,它是一個`i32`的引用,并不是`i32`本身。`println!`為我們處理了非關聯化,所以我們看不到。下面的代碼也能工作: ~~~ let nums = vec![1, 2, 3]; for num in &nums { println!("{}", *num); } ~~~ 現在我們顯式的解引用了`num`。為什么`&nums`會給我們一個引用呢?首先,因為我們顯式的使用了`&`。再次,如果它給我們數據,我們就是它的所有者了,這會涉及到生成數據的拷貝然后返回給我們拷貝。通過引用,我們只是借用了一個數據的引用,所以僅僅是傳遞了一個引用,并不涉及數據的移動。 那么,現在我們已經明確了范圍經產不是我們需要的,讓我們來討論下你需要什么。 這里涉及到大體上相關的3類事物:迭代器,_迭代適配器_(_iterator adapters_)和_消費者_(_consumers_)。下面是一些定義: * _迭代器_給你一個值的序列 * _迭代適配器_操作迭代器,產生一個不同輸出序列的新迭代器 * _消費者_操作迭代器,產生最終值的集合 讓我們先看看消費者,因為我們已經見過范圍這個迭代器了。 ## 消費者 _消費者_操作一個迭代器,返回一些值或者幾種類型的值。最常見的消費者是`collect()`。這個代碼還不能編譯,不過它表明了我們的意圖: ~~~ let one_to_one_hundred = (1..101).collect(); ~~~ 如你所見,我們在迭代器上調用了`collect()`。`collect()`從迭代器中取得盡可能多的值,然后返回結果的集合。那么為什么這不能編譯呢?因為Rust不能確定你想收集什么類型的值,所以你需要讓它知道。下面是一個可以編譯的版本: ~~~ let one_to_one_hundred = (1..101).collect::<Vec<i32>>(); ~~~ 如果你還記得,`::<>`語法允許我們給出一個類型提示,所以我們可以告訴編譯器我們需要一個整形的向量。但是你并不總是需要提供完整的類型。使用`_`可以讓你提供一個部分的提示: ~~~ let one_to_one_hundred = (1..101).collect::<Vec<_>>(); ~~~ 這是指“請把值收集到`Vec`,不過自行推斷`T`類型”。為此`_`有事被稱為“類型占位符”。 `collect()`是最常見的消費者,不過這還有其它的消費者。`find()`就是一個: ~~~ let greater_than_forty_two = (0..100) .find(|x| *x > 42); match greater_than_forty_two { Some(_) => println!("We got some numbers!"), None => println!("No numbers found :("), } ~~~ `find`接收一個閉包,然后處理迭代器中每個元素的引用。這個閉包返回`true`如果這個元素是我們要找的,返回`false`如果不是。因為我們可能不能找到任何元素,所以`find`返回`Option`而不是元素本身。 另一個重要的消費者是`fold`。他看起來像這樣: ~~~ let sum = (1..4).fold(0, |sum, x| sum + x); ~~~ `fold()`看起來像這樣:`fold(base, |accumulator, element| ...)`。它需要兩個參數:第一個參數叫做_基數_(_base_)。第二個是一個閉包,它自己也需要兩個參數:第一個叫做_累計數_(_accumulator_),第二個叫_元素_(_element_)。每次迭代,這個閉包都會被調用,返回值是下一次迭代的累計數。在我們的第一次迭代,基數是累計數。 好吧,這有點混亂。讓我們檢查一下這個迭代器中所有這些值: | 基數 | 累計數 | 元素 | 閉包結果 | | --- | --- | --- | --- | | 0 | 0 | 1 | 1 | | 0 | 1 | 2 | 3 | | 0 | 3 | 3 | 6 | 我們可以使用這些參數調用`fold()`: ~~~ .fold(0, |sum, x| sum + x); ~~~ 那么,`0`是我們的基數,`sum`是累計數,`x`是元素。在第一次迭代,我們設置`sum`為`0`,然后`x`是`nums`的第一個元素,`1`。我們接著把`sum`和`x`相加,得到`0 + 1 = 1`。在我們第二次迭代,`sum`成為我們的累計值,元素是數組的第二個值,`2`,`1 + 2 = 3`,然后它就是最后一次迭代的累計數。在這次迭代中,`x`是最后的元素,`3`,那么`3 + 3 = 6`,就是我們和的最終值。`1 + 2 + 3 = 6`,這就是我們的結果。 (口哨)。最開始你見到`fold`的時候可能覺得有點奇怪,不過一旦你習慣了它,你就會在到處都用它。任何時候你有一個列表,然后你需要一個單一的結果,`fold`就是合適的。 消費者很重要還因為另一個我們沒有討論到的迭代器的屬性:惰性。讓我們更多的討論一下迭代器,你就知道為什么消費者重要了。 ## 迭代器 正如我們之前說的,迭代器是一個我們可以重復調用它的`.next()`方法,然后它會給我們一個數據序列的結構。因為你需要調用函數,這意味著迭代器是_懶惰_(_lazy?_)的并且不需要預先生成所有的值。例如,下面的代碼并沒有真正的生成`1-100`這些數,而是創建了一個值來代表這個序列: ~~~ let nums = 1..100; ~~~ 因為我們沒有用范圍做任何事,它并生成序列。讓我們加上消費者: ~~~ let nums = (1..100).collect::<Vec<i32>>(); ~~~ 現在,`collect()`會要求范圍生成一些值,接著它會開始產生序列。 范圍是你會見到的兩個基本迭代器之一。另一個是`iter()`。`iter()`可以把一個向量轉換為一個簡單的按順序給出每個值的迭代器: ~~~ let nums = [1, 2, 3]; for num in nums.iter() { println!("{}", num); } ~~~ 這兩個基本迭代器應該能勝任你的工作。這還有一些高級迭代器,包括一個是無限的。像`count`: ~~~ std::iter::count(1, 5); ~~~ 這個迭代器從1開始計數,每次加5.它每次都會給你一個新值,直到永遠(好吧,從技術上講直到它循環到`i32`所能代表的最大值)。不過因為它是懶惰的,這沒有問題!你可能不會想在它之上使用`collect()`。 足夠關于迭代器的知識了。迭代適配器是關于迭代器最后一個要介紹的內容了。讓我們開始吧! ## 迭代適配器(Iterator adapters) _迭代適配器_(_Iterator adapters_)獲取一個迭代器然后按某種方法修改它,并產生一個新的迭代器。最簡單的是一個是`map`: ~~~ (1..100).map(|x| x + 1); ~~~ 在其他迭代器上調用`map`,然后產生一個新的迭代器,它的每個元素引用被調用了作為參數的閉包。所以它會給我們`2-100`這些數字。好吧,看起來是這樣。如果你編譯這個例子,你會得到一個警告: ~~~ warning: unused result which must be used: iterator adaptors are lazy and do nothing unless consumed, #[warn(unused_must_use)] on by default (1..100).map(|x| x + 1); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ 又是惰性!那個閉包永遠也不會執行。這個例子也不會打印任何數字: ~~~ (1..100).map(|x| println!("{}", x)); ~~~ 如果你嘗試在一個迭代器上執行帶有副作用的閉包,不如直接使用`for`。 這里有大量有趣的迭代適配器。`take(n)`會返回一個源迭代器下`n`個元素的新迭代器,注意這對源迭代器沒有副作用。讓我們試試我們之前的無限迭代器,`count()`: ~~~ for i in std::iter::count(1, 5).take(5) { println!("{}", i); } ~~~ 這會打印: ~~~ 1 6 11 16 21 ~~~ `filter()`是一個帶有一個閉包參數的適配器。這個閉包返回`true`或`false`。`filter()`返回的新迭代器只包含閉包返回`true`的元素: ~~~ for i in (1..100).filter(|&x| x % 2 == 0) { println!("{}", i); } ~~~ 這會打印出1到100之間所有的偶數。(注意因為`filter`并不消費它迭代的元素,它傳遞每個元素的引用,所以過濾器使用`&x`來獲取其中的整形數據。) 你可以鏈式的調用所有三種結構:以一個迭代器開始,適配幾次,然后處理結果。看看下面的: ~~~ (1..1000) .filter(|&x| x % 2 == 0) .filter(|&x| x % 3 == 0) .take(5) .collect::<Vec<i32>>(); ~~~ 這會給你一個包含`6`,`12`,`18`,`24`和`30`的向量。 這只是一個迭代器,迭代適配器和消費者如何幫助你的小嘗試。這里有很多非常實用的迭代器,當然你也可以編寫你自己的迭代器。迭代器提供了一個安全,高效的處理所有類型列表的方法。最開始它們顯得比較不尋常,不過如果你玩轉了它們,你就會上癮的。關于不同迭代器和消費者的列表,查看[迭代器模塊文檔](http://doc.rust-lang.org/std/iter/)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看