[英]Rust: how to assign `iter().map()` or `iter().enumarate()` to same variable
struct A {...whatever...};
const MY_CONST_USIZE:usize = 127;
// somewhere in function
// vec1_of_A:Vec<A> vec2_of_A_refs:Vec<&A> have values from different data sources and have different inside_item types
let my_iterator;
if my_rand_condition() { // my_rand_condition is random and compiles for sake of simplicity
my_iterator = vec1_of_A.iter().map(|x| (MY_CONST_USIZE, &x)); // Map<Iter<Vec<A>>>
} else {
my_iterator = vec2_of_A_refs.iter().enumerate(); // Enumerate<Iter<Vec<&A>>>
}
如何使這段代碼編譯?
最后(基於條件)我希望能夠從兩個輸入構建迭代器,但我不知道如何將這些Map
和Enumerate
類型集成到單個變量中,而不調用collect()
將迭代器具體化為Vec
或者它可能是反對的函數式編程原則
歡迎閱讀材料
在vec_of_A
的情況下,首先您需要在 map function 中將&x
替換為x
。 您擁有的代碼永遠不會編譯,因為映射閉包試圖返回對其參數之一的引用,這在 Rust 中是不允許的。 為了使類型匹配,您需要將vec2_of_A_refs
案例中的&&A
取消引用到&A
而不是嘗試添加對另一個的引用。
此外, -127
是usize
的無效值,因此您需要選擇一個有效值,或使用與usize
不同的類型。
修復了這些,現在您需要某種類型的動態調度。 最簡單的方法是裝箱成Box<dyn Iterator>
。
這是一個完整的例子:
#![allow(unused)]
#![allow(non_snake_case)]
struct A;
// Fixed to be a valid usize.
const MY_CONST_USIZE: usize = usize::MAX;
fn my_rand_condition() -> bool { todo!(); }
fn example() {
let vec1_of_A: Vec<A> = vec![];
let vec2_of_A_refs: Vec<&A> = vec![];
let my_iterator: Box<dyn Iterator<Item=(usize, &A)>>;
if my_rand_condition() {
// Fixed to return x instead of &x
my_iterator = Box::new(vec1_of_A.iter().map(|x| (MY_CONST_USIZE, x)));
} else {
// Added map to deref &&A to &A to make the types match
my_iterator = Box::new(vec2_of_A_refs.iter().map(|x| *x).enumerate());
}
for item in my_iterator {
// ...
}
}
( 游樂場)
除了盒裝特征 object,您還可以使用either
一板條箱中的Either
類型。 這是一個具有Left
和Right
變體的枚舉,但是如果 left 和 right 類型也都這樣做,則Either
類型本身實現Iterator
,並且Item
關聯類型具有相同的類型。 例如:
#![allow(unused)]
#![allow(non_snake_case)]
use either::Either;
struct A;
const MY_CONST_USIZE: usize = usize::MAX;
fn my_rand_condition() -> bool { todo!(); }
fn example() {
let vec1_of_A: Vec<A> = vec![];
let vec2_of_A_refs: Vec<&A> = vec![];
let my_iterator;
if my_rand_condition() {
my_iterator = Either::Left(vec1_of_A.iter().map(|x| (MY_CONST_USIZE, x)));
} else {
my_iterator = Either::Right(vec2_of_A_refs.iter().map(|x| *x).enumerate());
}
for item in my_iterator {
// ...
}
}
( 游樂場)
為什么你會選擇一種方法而不是另一種?
Either
方法的優點:
match
實現動態調度,這可能(但不保證)比通過 vtable 查找的動態調度更快。盒裝特征 object 方法的優點:
Either
方法很快就會變得笨拙。您可以使用Box
ed trait object 來執行此操作,如下所示:
let my_iterator: Box<dyn Iterator<Item = _>> = if my_rand_condition() {
Box::new(vec1_of_A.iter().map(|x| (MY_CONST_USIZE, x)))
} else {
Box::new(vec2_of_A_refs.iter().enumerate().map(|(i, x)| (i, *x)))
};
不過,我認為這通常不是一個好主意。 需要注意的幾點:
vec1
的迭代器的map
方法中的閉包無法引用其 arguments。 相反,必須將第二個map
添加到vec2
的迭代器中。 這樣做的效果是無論如何都將復制所有項目。 如果你這樣做,為什么不collect()
? 創建Vec
或您選擇的任何內容的開銷應小於動態分辨率的開銷。if
語句是 Rust 中的表達式,因此可以像我上面所做的那樣更清晰地表達賦值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.