首页 文章

如何返回对filter_map的调用结果

提问于
浏览
2

这里我有一个(char,usize)对的矢量vec,我想写一个函数

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

它返回一个迭代器,它在匹配值小于cutoff的字符上 .

  • 有没有办法做到这一点,没有分配东西堆的开销(即装箱Fn环境或创建另一个向量)?

  • 有没有办法做到这一点
    无需明确写出可怕的关联返回类型?

在尝试了许多不同的方法(其中一些已编译,但所有这些都涉及堆分配,我想避免),我想出了:

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)
                                                            ^~~~~~~~

一点google搜索建议我尝试将函数项转换为函数指针,如:

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
              ...

2 回答

  • 1

    你很亲密:

    // 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 }
    }
    
  • 3

    每个函数都有一个独特的,不同的类型,与 fn 类型兼容 . 这反映了闭包也有不同类型的事实 . 这是编译器通过 found fn item 的含义:它没有找到您在返回类型中指定的 fn 类型,而是 cmp_fun 函数的唯一类型 .

    fn 类型已经是指针,所以不需要(至少在你的情况下)引用 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)
    }
    

相关问题