2015-12-25 66 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) 
}