2015-12-25 98 views
2

在這裏,我有(焦炭,USIZE)對一個向量VEC,我想編寫一個函數如何返回調用的結果filter_map

fn take_lt(&'a vec, cutoff: usize) -> Iterator<'a, char> 

返回了匹配值的字符的迭代器小於臨界值。

  1. 有沒有辦法做到這一點,而沒有分配東西堆(即裝箱Fn環境或創建另一個向量)的開銷?
  2. 有沒有辦法做到這一點
    而不必明確寫出可怕的關聯返回 類型?

嘗試這許多不同的方式後(一對夫婦的編制了,但所有這些都涉及我想避免堆分配),我想出了:

use std::iter::repeat; 
use std::iter::FilterMap; 
use std::iter::Zip; 
use std::iter::Repeat; 
use std::slice; 

fn take_lt<'a>(vec: &'a[(char, usize)], cutoff: usize) -> FilterMap<Zip<slice::Iter<'a, (char, usize)>, Repeat<usize>>, &fn((&(char, usize), usize)) -> Option<char>> { 
    fn cmp_fun((&(x, a), b): (&(char, usize), usize)) -> Option<char> { 
     if a < b { 
      Some(x) 
     } else { 
      None 
     } 
    } 
    vec.iter().zip(repeat(cutoff)).filter_map(&cmp_fun) 
} 

這是接近,但我得到:

src/lib.rs:15:47: 15:55 error: mismatched types: 
expected `&fn((&(char, usize), usize)) -> core::option::Option<char>`, 
    found `&fn((&(char, usize), usize)) -> core::option::Option<char> {take_lt::cmp_fun}` 
(expected fn pointer, 
    found fn item) [E0308] 
src/lib.rs:15  vec.iter().zip(repeat(cutoff)).filter_map(&cmp_fun) 
                  ^~~~~~~~ 

一個小Googling建議我嘗試鑄造的功能項目函數指針,如:

vec.iter().zip(repeat(cutoff)).filter_map(&(cmp_fun as fn((&(char, usize), usize)) -> Option<char>)) 

但失敗:

src/lib.rs:15:49: 15:103 error: borrowed value does not live long enough 
src/lib.rs:15  vec.iter().zip(repeat(cutoff)).filter_map(&(cmp_fun as fn((&(char, usize), usize)) -> Option<char>)) 
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/lib.rs:7:167: 16:2 note: reference must be valid for the lifetime 'a as defined on the block at 7:166... 
src/lib.rs: 7 fn take_lt<'a>(vec: &'a[(char, usize)], cutoff: usize) -> FilterMap<Zip<slice::Iter<'a, (char, usize)>, Repeat<usize>>, &fn((&(char, usize), usize)) -> Option<char>> { 
src/lib.rs: 8  fn cmp_fun((&(x, a), b): (&(char, usize), usize)) -> Option<char> { 
src/lib.rs: 9   if a < b { 
src/lib.rs:10    Some(x) 
src/lib.rs:11   } else { 
src/lib.rs:12    None 
       ... 
src/lib.rs:7:167: 16:2 note: ...but borrowed value is only valid for the block at 7:166 
src/lib.rs: 7 fn take_lt<'a>(vec: &'a[(char, usize)], cutoff: usize) -> FilterMap<Zip<slice::Iter<'a, (char, usize)>, Repeat<usize>>, &fn((&(char, usize), usize)) -> Option<char>> { 
src/lib.rs: 8  fn cmp_fun((&(x, a), b): (&(char, usize), usize)) -> Option<char> { 
src/lib.rs: 9   if a < b { 
src/lib.rs:10    Some(x) 
src/lib.rs:11   } else { 
src/lib.rs:12    None 
       ... 
+0

http://stackoverflow.com/questions/27535289/correct-way-to-return-an-iterator的副本。 – Shepmaster

回答

3

你接近:

// type alias for the return type (optional, I just find it a bit 
// optically easier to work with). I added: 
// a 'a lifetime parameter that ties the return Iter lifetime to the 
// input slice 
// a 'static lifetime for the function pointer 
type RetTake<'a> = FilterMap<Zip<slice::Iter<'a, (char, usize)>, 
    Repeat<usize>>, &'static fn((&(char, usize), usize)) -> Option<char>>; 

fn take_lt<'a>(vec: &'a[(char, usize)], cutoff: usize) -> RetTake { 
    fn cmp_fun((&(x, a), b): (&(char, usize), usize)) -> Option<char> { 
     if a < b { 
      Some(x) 
     } else { 
      None 
     } 
    } 

    // I think this explicit static binding 
    // used not to be necessary, but I now can't get rustc 
    // to give the reference to the function pointer the static lifetime 
    // it needs otherwise 
    static F: fn((&(char, usize), usize)) -> Option<char> = cmp_fun; 
    vec.iter().zip(repeat(cutoff)).filter_map(&F) 
} 

,你可以創建自己的結構實現你所需要的迭代器邏輯並返回一個結構的替代品。例如:

struct CutoffIterator<'a> { 
    iter: slice::Iter<'a, (char, usize)>, 
    cutoff: usize, 
} 

impl<'a> Iterator for CutoffIterator<'a> { 
    type Item = char; 

    fn next(&mut self) -> Option<char> { 
     loop { 
      match self.iter.next() { 
       Some(&(x, a)) if a < self.cutoff => return Some(x), 
       Some(&(_, a)) if a >= self.cutoff => continue, 
       _ => return None 
      } 
     } 
    } 
} 

fn take_lt2(vec: &[(char, usize)], cutoff: usize) -> CutoffIterator { 
    CutoffIterator { iter: vec.iter(), cutoff: cutoff } 
} 
+0

我從來沒有見過(靜態F ...)之前。你能指出我在哪裏可以找到更多關於它的信息嗎? – dspyz

+0

還有一種方法可以避免.zip(repeat())破解,並直接將環境保存爲迭代器的一部分? – dspyz

+0

@dspyz靜態變量包含在本書的[const和static部分](https://doc.rust-lang.org/stable/book/const-and-static.html)中。 F是一種類型爲「指向函數的指針」的靜態變量 –

1

每個函數都有獨特的不同類型,與fn類型兼容。這反映了關閉也具有不同類型的事實。這是編譯器通過found fn item表示的含義:它沒有找到您在返回類型中指定的fn類型,而是cmp_fun函數的唯一類型。

fnfn類型已經是指針了,所以沒有必要(至少在你的情況下)引用fn;你可以直接採取fn。通過這樣做,編譯器將隱式地將該函數轉換爲更一般的fn類型。

fn take_lt<'a>(vec: &'a[(char, usize)], cutoff: usize) -> FilterMap<Zip<slice::Iter<'a, (char, usize)>, Repeat<usize>>, fn((&(char, usize), usize)) -> Option<char>> { 
    fn cmp_fun((&(x, a), b): (&(char, usize), usize)) -> Option<char> { 
     if a < b { 
      Some(x) 
     } else { 
      None 
     } 
    } 
    vec.iter().zip(repeat(cutoff)).filter_map(cmp_fun) 
}