这里我有一个(char,usize)对的矢量vec,我想写一个函数
fn take_lt(&'a vec, cutoff: usize) -> Iterator<'a, char>
返回匹配值小于cutoff的字符上的迭代器。
在尝试了许多不同的方法(其中一些已经编译,但所有这些都涉及我希望避免的堆分配)之后,我提出了:
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)
^~~~~~~~
有点谷歌搜索建议我尝试将函数项转换为函数指针,如:
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 :(得分: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 }
}
答案 1 :(得分:1)
每个函数都有一个独特的,不同的类型,与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)
}