使用修改后的`Chars`迭代器时,生命周期参数的数量错误

web*_*tee 5 iterator traits lifetime rust

我想为IntoIterator包含a的结构实现trait String.迭代器基于chars()迭代器,应该计算'1'字符并累积结果.这是我到目前为止的简化版本:

use std::iter::Map;
use std::str::Chars;

fn main() {
    let str_struct = StringStruct { system_string: String::from("1101") };
    for a in str_struct {
        println!("{}", a);
    }
}

struct StringStruct {
    system_string: String
}

impl IntoIterator for StringStruct {
    type Item = u32;
    type IntoIter = Map<Chars, Fn(char) -> u32>;

    fn into_iter(self) -> Self::IntoIter {
        let count = 0;
        return self.system_string.chars().map(|c| match c {
            Some('1') => {
                count += 1;
                return Some(count);
            },
            Some(chr) => return Some(count),
            None => return None
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

预期产量: 1, 2, 2, 3

这失败了:

error[E0107]: wrong number of lifetime parameters: expected 1, found 0
  --> src/main.rs:17:25
   |
17 |     type IntoIter = Map<Chars, Fn(char) -> u32>;
   |                         ^^^^^ expected 1 lifetime parameter
Run Code Online (Sandbox Code Playgroud)

字符迭代器应该具有相同的生命周期StringStruct::system_string,但我不知道如何表达这个或者这种方法是否可行.

Luk*_*odt 5

要回答你问的问题,我建议impl IntoIterator for &StringStruct(直接引用一个StringStruct结构代替结构).代码如下所示:

impl<'a> IntoIterator for &'a StringStruct {
    type Item = u32;
    type IntoIter = Map<Chars<'a>, Fn(char) -> u32>;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,您会注意到之后有更多不同来源的错误.弹出的下一个错误是Fn(char) -> u32在编译时没有常量大小.

问题是您尝试通过编写来命名闭包的类型Fn(char) -> u32.但这不是你的闭包的类型,而只是闭包实现的特征.无法命名闭包的类型(有时称为"Voldemort类型").

这意味着,您现在无法指定Map<_, _>对象的类型.这是一个已知的问题; 最近接受的impl Trait-RFC可能会为此类案例提供解决方法.但是现在,这是不可能的,对不起.

那么如何解决呢?您需要创建自己的类型来实现Iterator和使用它而不是Map<_, _>.请注意,您仍然可以使用Chars迭代器.这是完整的解决方案:

struct StringStructIter<'a> {
    chars: Chars<'a>,
    count: u32,
}

impl<'a> Iterator for StringStructIter<'a> {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
         self.chars.next().map(|c| {
            if c == '1' {
                self.count += 1;
            }
            self.count
        })
    }
}

impl<'a> IntoIterator for &'a StringStruct {
    type Item = u32;
    type IntoIter = StringStructIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
         StringStructIter {
             chars: self.system_string.chars(),
             count: 0,
         }
    }
}

fn main() {
    let str_struct = StringStruct { system_string: String::from("1101") };
    for a in &str_struct {
        println!("{}", a);
    }
}
Run Code Online (Sandbox Code Playgroud)

而且只是一个小小的注释:return在不必要的情况下明确表示Rust中的不良风格.通过return尽可能删除来更好地坚持规则并编写惯用代码;-)