在Rust我已經開始編寫迭代器,將它們從帶回調函數的代碼轉換而來。編寫支持多邏輯分支的迭代器的最佳方式是什麼?
我遇到了在函數的多個分支中使用回調的代碼沒有如此乾淨地轉換爲Rust迭代器的問題。
給一些僞代碼。
// function using callbacks where the caller can exit at any time,
// can be used in a similar way to an iterator.
fn do_stuff(args, callback_fn(cb_args)) {
// define a, b, c... args
if callback_fn(a, b, 0) == false { return; }
for i in 0..n {
if callback_fn(c, d, i) == false { return; }
}
if callback_fn(e, f, -1) == false { return; }
}
將此轉換爲迭代器相當笨拙,因爲我需要存儲一些代表每個分支的狀態。
impl Iterator for MyStruct {
fn next(&mut self) -> Option<MyResult> {
let out = match (self.state) {
0 => {
self.state += 1;
Some(MyResult(self.a, self.b, 0))
},
1 => {
self.i += 1;
if self.i == self.n {
self.state += 1;
}
Some(MyResult(self.c, self.d, self.i - 1))
},
2 => {
self.state += 1;
Some(MyResult(self.e, self.f, -1))
},
_ => {
None
},
}
return out;
}
// --- snip
隨着上面的例子,這可以說是可以接受的,(如果有點笨拙)。考慮具有多個for循環,變量作用域的情況,其中很難跟蹤狀態。
雖然我沒有嘗試這些,我想有一些方法來實現這一目標,在大多數情況下是不太那麼理想的解決方法:
- 使用回調版本,構建向量,然後迭代它...
(工作但失敗了使用迭代器的目的,無法提前退出並避免爲例如創建整個數據集)。 - 編寫一個與使用與回調版本類似邏輯的線程進行通信的迭代器。
(儘管可能,創建操作系統線程的開銷使得它在許多情況下是一個糟糕的選擇)。
除了上述的變通辦法:
是否有辦法來寫這樣給出的例子迭代器,以較少的令人費解的邏輯?
理想情況下更像使用回調的示例。
否則有其他方法可以解決這個問題嗎?
或者這只是在Rust不支持?
注意,相同的邏輯適用從Python生成未來(使用收率代替回調的,使用回調作爲例子在這裏,因爲他們是無處不在的一流函數)。
使用'match'而不是if-else並省略'return'使得代碼[更好一點](https://gist.github。com/LukasKalbertodt/9f2e73305880e586231b76ef4b6a948c)已經,不是嗎? :) –
@LukasKalbertodt,右,編輯使用匹配,但是這並沒有解決問題的根源 - 移動使用回調到迭代器的複雜函數是非平凡的,結果代碼通常不易讀或易於使用維護,例如 - https://gitlab.com/ideasman42/rust-simple-examples/blob/master/draw_poly_2d_callback/src/main.rs。 – ideasman42