使用flat_map将Vec<u8>转换为Vec<char>

4

我陷入了与Borrow-check error with variable not living long enough in nested lambda类似的困境,但无法确定我的情况有何不同:

let mut vec = vec![vec![0u8, 1u8], vec![2u8, 3u8], vec![4u8, 5u8]];
vec.iter().map(|row| {
    row.iter()
        .map(|d| format!("{:04b}", d))
        .flat_map(|s| s.chars())
        .collect::<Vec<_>>()
});

导致错误的原因:

error[E0597]: `s` does not live long enough
 --> src/main.rs:6:35
  |
6 |             .flat_map(|s| s.chars())
  |                           -       ^ `s` dropped here while still borrowed
  |                           |
  |                           borrow occurs here
7 |             .collect::<Vec<_>>()
  |                                - borrowed value needs to live until here

我通过创建一个新的 Vec 并进行附加来解决它,但我不清楚为什么第一种方法不起作用。
let mut tmp = vec![];
vec.iter()
    .map(|d| format!("{:04b}", d))
    .for_each(|s| {tmp.append(&mut s.chars().collect::<Vec<_>>());});

当您调用chars()时,您借用s来创建一个包含对其引用的Char结构体。当您退出闭包时,s被丢弃,因此Char无效。 - Boiethios
@Boiethios 这正是文档的确切方式。为什么这里不起作用呢? - Andrew
1
@Andrew,那个例子使用了静态字符串。在你的例子中,字符串是在迭代器内部创建的,所以它们的生命周期不够长。 - Sven Marnach
1
请参考如何在与其迭代的字符串相同的结构体中存储Chars迭代器?,其中包含一个版本的.chars(),它将转移String的所有权,并因此在这种情况下起作用。 - Shepmaster
1个回答

3
你需要先将闭包 |d| format!("{:04b}", d) 映射到迭代器上,得到拥有自己数据的String,这样就可以完美地工作了。接下来,flat_map() 在下一步对每个String 调用 .chars()。这会隐式地将String解引用为一个&str,并创建一个引用这个借用的Chars 迭代器。但是现在我们有了一个问题——没有人再拥有我们借用的String了。
一个解决方法是存储一个临时的String向量:
let mut vec = vec![vec![0u8, 1u8], vec![2u8, 3u8], vec![4u8, 5u8]];
vec.iter().map(|row| {
    let strings: Vec<_> = row
        .iter()
        .map(|d| format!("{:04b}", d))
        .collect();
    strings
        .iter()
        .flat_map(|s| s.chars())
        .collect::<Vec<_>>()
});

现在我们为中介字符串拥有一个所有者,一切都正常工作了。

也许我们应该为String提供一个消耗版本的chars,以防止这种样板文件的出现。 - Boiethios
@Boiethios:昨天我很惊讶地发现我找不到一个FromIterator的实现。 - Matthieu M.
@MatthieuM。似乎很容易做到。如果此添加不会引起任何破坏性更改,也许有人(你?我?)应该提出一些建议。 - Boiethios
@Boiethios:请继续 :) - Matthieu M.
1
谢谢解释。我只学了两周的 Rust,所以还在学习所有权。慢慢来。因此,由于 chars 是从 StrExt 特性实现的 str 而不是 String,它通过 Deref<Target = str>String 转换为 str,然后传递给 chars(&self)?这意味着如果有一个版本的 chars(self) 它会工作吗? - Andrew
@Andrew 没错,你完美地总结了这个问题 :) - Boiethios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接