亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

有條件地迭代幾個可能的迭代器之一

有條件地迭代幾個可能的迭代器之一

紅顏莎娜 2019-10-04 14:17:14
我正在嘗試根據功能的Option輸入來切換行為。這個想法是基于給定Option是否存在進行迭代。這是一個最小的(如果很愚蠢的)示例:use std::iter;fn main() {    let x: Option<i64> = None;    // Repeat x 5 times if present, otherwise count from 1 to 5    for i in match x {        None => 1..5,        Some(x) => iter::repeat(x).take(5),    } {        println!("{}", i);    }}我收到一個錯誤:error[E0308]: match arms have incompatible types  --> src/main.rs:7:14   |7  |       for i in match x {   |  ______________^8  | |         None => 1..5,9  | |         Some(x) => iter::repeat(x).take(5),   | |                    ----------------------- match arm with an incompatible type10 | |     } {   | |_____^ expected struct `std::ops::Range`, found struct `std::iter::Take`   |   = note: expected type `std::ops::Range<{integer}>`              found type `std::iter::Take<std::iter::Repeat<i64>>`當然,這完全有道理,但是我真的很想根據條件選擇迭代器,因為for循環中的代碼很簡單,而復制粘貼所有這些只是為了更改迭代器選擇就相當了丑陋且難以維護。我嘗試as Iterator<Item = i64>兩臂同時使用,但是這給我帶來了有關未定型類型的錯誤,因為它是一個特征對象。有一個簡單的方法可以解決這個問題嗎?我可以使用,.collect()因為它們返回相同的類型并遍歷該向量。這是一個很好的快速解決方案,但對于大型列表而言似乎有點多余。
查看完整描述

3 回答

?
慕虎7371278

TA貢獻1802條經驗 獲得超4個贊

的任一箱提供Either類型。如果兩個Either都是迭代器,則Either:也是


extern crate either;


use either::Either;

use std::iter;


fn main() {

    let x: Option<i64> = None;


    // Repeat x 5 times if present, otherwise count from 1 to 5

    let iter = match x {

        None => Either::Left(1..5),

        Some(x) => Either::Right(iter::repeat(x).take(5)),

    };


    for i in iter {

        println!("{}", i);

    }

}

像先前的答案一樣,這仍然會占用每種具體類型的堆??臻g。但是,您不需要為每個具體值使用單獨的變量。


也可以從函數返回此類型,這與trait對象引用不同。與盒裝特征對象相比,無論選擇哪種具體類型,它都將始終在堆棧上使用固定大小。


您還會在其他地方找到這種類型(或語義等效),例如 futures::Either


查看完整回答
反對 回復 2019-10-04
?
瀟湘沐

TA貢獻1816條經驗 獲得超6個贊

您需要引用一個特征:


use std::iter;


fn main() {

    let mut a;

    let mut b;


    let x: Option<i64> = None;


    // Repeat x 5 times if present, otherwise count from 1 to 5

    let iter: &mut Iterator<Item = i64> = match x {

        None => {

            a = 1..5;

            &mut a

        }

        Some(x) => {

            b = iter::repeat(x).take(5);

            &mut b

        }

    };


    for i in iter {

        println!("{}", i);

    }

}

該解決方案的主要缺點是,您必須為每種具體類型分配堆??臻g。這也意味著每種類型的變量。一件好事是只需要初始化使用的類型。


相同的想法但需要堆分配的是使用裝箱的特征對象:


use std::iter;


fn main() {

    let x: Option<i64> = None;


    // Repeat x 5 times if present, otherwise count from 1 to 5

    let iter: Box<Iterator<Item = i64>> = match x {

        None => Box::new(1..5),

        Some(x) => Box::new(iter::repeat(x).take(5)),

    };


    for i in iter {

        println!("{}", i);

    }

}

當您要從函數返回迭代器時,這最有用。占用的堆??臻g是單個指針,并且只會分配所需的堆空間。


查看完整回答
反對 回復 2019-10-04
?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

就個人而言,Either我通常更喜歡創建一系列Option<Iterator>鏈接在一起的價值觀,而不是使用。像這樣:


操場


use std::iter;


fn main() {

    let x: Option<i64> = None;


    // Repeat x 5 times if present, otherwise count from 1 to 5

    for i in pick(x) {

        println!("{}", i);

    }

}


fn pick(opt_x: Option<i64>) -> impl Iterator<Item = i64> {

    let iter_a = if let None = opt_x {

        Some(1..5)  

    } else {

        None

    };


    let iter_b = if let Some(x) = opt_x {

        Some(iter::repeat(x).take(5))

    } else {

        None

    };


    iter_a.into_iter().flatten().chain(iter_b.into_iter().flatten())

}

與使用相比Either,它不那么明顯,但是它避免了使用其他板條箱,有時效果非常好。


查看完整回答
反對 回復 2019-10-04
  • 3 回答
  • 0 關注
  • 573 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號