Rust程式語言融合了多種程式設計法(programming paradigm),其中的指令式程式設計(imperative programming)所用的迴圈和函數式程式設計(functional programming)所提供的迭代器(iterator)設計模式有著功能上的重疊,那麼究竟應該要用哪種才比較有效率呢?



走訪陣列

以走訪一個整數陣列,印出其所有元素值,並且將元素值改為0為例,使用Rust程式語言可以有以下幾種寫法。

For計次迴圈

使用一個整數變數來儲存每次執行迴圈時,要存取的陣列元素之索引位置。常會搭配範圍(range)語法一同使用。例如:

for i in 0..array.len() {
    println!("{}", array[i]);
    array[i] = 0;
}

For迭代器迴圈

將For迴圈搭配迭代器一起使用。例如:

for e in array.iter_mut() {
    println!("{}", *e);
    *e = 0;
}

迭代器

完全使用迭代器的函數式程式設計模式,搭配閉包來處理每次迭代要進行的動作。例如:

array.iter_mut().for_each(|e| {
    println!("{}", e);
    *e = 0;
});

堆疊內的陣列和堆積內的陣列?

根據這篇文章的分析:

既然堆疊內的陣列和堆積內的陣列有效能上的差異,那麼使用不同方式走訪堆疊或是堆積內的陣列,效能是否也存在著差異?會不會其實有某種組合能有機會讓堆積內的陣列能夠走訪的比堆疊內的陣列還快?

如果陣列其實是切片呢?

在實際開發程式的時候,常常會去取得陣列的切片來用。將陣列轉成切片之後,它存取速度還是一樣的嗎?

效能實測

為了釐清用不同的方式走訪在堆疊內或是在堆積內的陣列,以及如果陣列實際上是切片的話對效能的影響,就要實際寫一段程式來測試運算效能啦!這段程式可以在GitHub上取得:

我們先將這些不同的陣列分為以下幾類:

1. 堆疊中的陣列。
2. 堆疊中的陣列切片。
3. 堆積中的陣列。
4. 堆積中的陣列切片。

再根據其走訪方式的不同,分為:

1. 用For計次迴圈走訪堆疊中的陣列。
2. 用For迭代器迴圈走訪堆疊中的陣列。
3. 用迭代器走訪堆疊中的陣列。
4. 用For計次迴圈走訪堆疊中的陣列切片。
5. 用For迭代器迴圈走訪堆疊中的陣列切片。
6. 用迭代器走訪堆疊中的陣列切片。
7. 用For計次迴圈走訪堆積中的陣列。
8. 用For迭代器迴圈走訪堆積中的陣列。
9. 用迭代器走訪堆積中的陣列。
10. 用For計次迴圈走訪堆積中的陣列切片。
11. 用For迭代器迴圈走訪堆積中的陣列切片。
12. 用迭代器走訪堆積中的陣列切片。

實測的效能排名如下:

1. 用For計次迴圈走訪堆疊中的陣列、用For迭代器迴圈走訪堆疊中的陣列、用迭代器走訪堆疊中的陣列(又略比另兩者好)。
2. 用For迭代器迴圈走訪堆疊中的陣列切片、用迭代器走訪堆疊中的陣列切片、用For迭代器迴圈走訪堆積中的陣列、用迭代器走訪堆積中的陣列、用For迭代器迴圈走訪堆積中的陣列切片、用迭代器走訪堆積中的陣列切片。
3. 用For計次迴圈走訪堆疊中的陣列切片、用For計次迴圈走訪堆積中的陣列、用For計次迴圈走訪堆積中的陣列切片。

根據測試結果,我們可以得到一個結論,那就是應該要儘量使用迭代器來走訪陣列,並且除非是在走訪堆疊中的陣列,不然要儘量避免使用For計次迴圈。另外,要保持堆疊中的陣列的效能,就不要將其轉為切片。