2016-04-03 84 views
1

我試圖通過在一個小日曆項目上工作來教自己鏽。Rust:如何從函數返回一個迭代器並使用它?

在這裏,我試圖生成一個約定在一個給定日期三個整月的日期列表。 我想返回一個可以迭代這些日期的迭代器。 這是我第一次嘗試:

fn three_months_range(tm: time::Tm) -> std::iter::Iterator<Item=time::Tm> { 
    let fpm: time::Tm = first_of_previous_month(&tm); 
    (0..) 
     .map(|i| fpm + time::Duration::days(i)) 
     .take_while(|&t| t.tm_mon != (tm.tm_mon + 2) % 12) 
} 

不幸的是,這並不編譯,我得到一個錯誤。

src/main.rs:49:40: 49:75 error: the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator<Item=time::Tm> + 'static` [E0277] 
src/main.rs:49 fn three_months_range(tm: time::Tm) -> std::iter::Iterator <Item=time::Tm> { 
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:49:40: 49:75 help: run `rustc --explain E0277` to see a detailed explanation 
src/main.rs:49:40: 49:75 note: `core::iter::Iterator<Item=time::Tm> + 'static` does not have a constant size known at compile-time 
src/main.rs:49:40: 49:75 note: the return type of a function must have a statically known size 

「函數的返回類型必須具有靜態已知大小」。好的,經過一番研究,似乎解決方案是通過Box返回迭代器。我仍然想知道標準庫map,filtertake_while ...方法如何管理返回迭代器而不是盒子)。

嗯,這裏是第二次嘗試,成功編譯:

fn three_months_range(tm: time::Tm) -> Box<iter::Iterator<Item=time::Tm>> { 
    let fpm: time::Tm = first_of_previous_month(&tm); 
    Box::new(
     (0..) 
     .map(move |i| fpm + time::Duration::days(i)) 
     .take_while(move |&t| t.tm_mon != (tm.tm_mon + 2) % 12) 
    ) 
} 

不幸的是,我不管理使用這個迭代器。 例如,假設我想構建一個包含每個日期的月份日期(1,2,3,...,31,1,2,...,30,1,2,...)的向量。 31):

let days_vec: Vec<u64> = 
    (*three_months_range(time::now_utc())) 
    .map(|&t: &time::Tm| t.tm_mday) 
    .collect(); 

src/main.rs:14:10: 14:42 error: the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator<Item=time::Tm> + 'static` [E0277] 
src/main.rs:14   .map(|&t: &time::Tm| t.tm_mday) 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:14:10: 14:42 help: run `rustc --explain E0277` to see a detailed explanation 
src/main.rs:14:10: 14:42 note: `core::iter::Iterator<Item=time::Tm> + 'static` does not have a constant size known at compile-time 
src/main.rs:15:10: 15:19 error: no method named `collect` found for type `core::iter::Map<core::iter::Iterator<Item=time::Tm> + 'static, [[email protected]/main.rs:14:15: 14:40]>` in the current scope 
src/main.rs:15   .collect(); 
         ^~~~~~~~~ 
src/main.rs:15:10: 15:19 note: the method `collect` exists but the following trait bounds were not satisfied: `core::iter::Iterator<Item=time::Tm> : core::marker::Sized`, `[[email protected]/main.rs:14:15: 14:40] : core::ops::FnMut<(time::Tm,)>`, `core::iter::Map<core::iter::Iterator<Item=time::Tm> + 'static, [[email protected]/main.rs:14:15: 14:40]> : core::iter::Iterator` 
src/main.rs:14:10: 14:42 error: type mismatch: the type `[[email protected]/main.rs:14:15: 14:40]` implements the trait `for<'r> core::ops::FnMut<(&'r time::Tm,)>`, but the trait `core::ops::FnMut<(time::Tm,)>` is required (expected struct `time::Tm`, found &-ptr) [E0281] 
src/main.rs:14   .map(|&t: &time::Tm| t.tm_mday) 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:14:10: 14:42 help: run `rustc --explain E0281` to see a detailed explanation 
src/main.rs:14:10: 14:42 error: type mismatch: the type `[[email protected]/main.rs:14:15: 14:40]` implements the trait `for<'r> core::ops::FnOnce<(&'r time::Tm,)>`, but the trait `core::ops::FnOnce<(time::Tm,)>` is required (expected struct `time::Tm`, found &-ptr) [E0281] 
src/main.rs:14   .map(|&t: &time::Tm| t.tm_mday) 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:14:10: 14:42 help: run `rustc --explain E0281` to see a detailed explanation 
error: aborting due to 4 previous errors 

這是一個很大的錯誤。

那麼我在這裏做錯了什麼?

有沒有一種相對簡單的方法來轉換Rust中的迭代器和/或從函數中返回它們?

+0

注意:你嘗試過回' - >()'從功能,讓編譯器告訴你什麼是你創建的迭代器的確切類型,然後使用這個具體鍵入而不是特質? –

+0

我得到的類型是:'core :: iter :: TakeWhile ,[[email protected]/main.rs:64:15:64:53 fpm :_]>,[[email protected]/main.rs:64:66:64:113 tm:_]>' –

+0

關閉會讓你進入一個泡菜,他們的類型不能被命名,我看不到明顯的方式在這個特殊情況下將功能提升爲裸函數不幸的是:( –

回答

3

問題是您正試圖將IteratorBox中刪除(因爲它不是特徵對象,因此不是Sized)。但Box是透明的,可以直接使用就可以了map

let days_vec: Vec<u64> = 
    three_months_range(time::now_utc()) 
    .map(|&t: &time::Tm| t.tm_mday) 
    .collect(); 

注意,map函數需要按值,而不是採取論證的參考。因此,呼叫可以是這樣的:

.map(|t| t.tm_mday) 
+0

)謝謝!這是行得通的。我不完全理解爲什麼你不能取消引用一個盒子,爲什麼所有的Iterator關聯方法都在Box上實現。我想我必須閱讀更多關於盒子的知識,但文檔對他們來說似乎很少。 –

+1

「盒子」一般是特殊的,它有[deref強制](https://doc.rust-lang.org/book/ DEREF-的強制。html) –

+0

感謝您的鏈接 –

相關問題