【问题标题】:Use flat_map to convert Vec<u8> to Vec<char>使用 flat_map 将 Vec<u8> 转换为 Vec<char>
【发布时间】:2017-12-14 21:30:21
【问题描述】:

我陷入与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 这是documentation 的确切方式。为什么它在那里工作而不在这里工作?
  • @Andrew 该示例使用静态字符串。在您的示例中,字符串是在迭代器中创建的,因此它们的寿命不够长。
  • 请参阅How can I store a Chars iterator in the same struct as the String it is iterating on? 以获取.chars() 的版本,该版本将转移String 的所有权并因此适用于这种情况。

标签: rust borrow-checker


【解决方案1】:

您首先将闭包|d| format!("{:04b}", d) 映射到您的迭代器上,产生Strings,它拥有他们的数据,所以这完美地找到了。下一步中的flat_map() 在每个String 上调用.chars()。这隐含地将String 取消引用到&amp;str,并创建一个引用此借用的Chars 迭代器。但现在我们遇到了一个问题——没有人拥有我们借用的String

一种解决方法是存储Strings 的临时向量:

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<_>>()
});

现在我们有了中间人Strings 的所有者,一切都恢复正常了。

【讨论】:

  • 也许我们应该为String 使用chars 的消费版本来防止这种样板。
  • @Boiethios:昨天我很惊讶地发现我找不到 FromIterator 的实现。
  • @MatthieuM。做起来似乎微不足道。如果此添加不会引起任何重大变化,那么也许有人(你?我?)应该提出一些建议。
  • @Boiethios:请继续 :)
  • 感谢您的解释。我只生锈了 2 周,所以还在学习所有权。慢慢地。因此,因为chars 来自StrExt 特征,它在str 而不是String 上实现,所以它从String 转换为str,通过Deref&lt;Target = str&gt; 然后传递到chars(&amp;self)?意思是如果有一个版本的chars(self) 它会起作用?
猜你喜欢
  • 2020-10-28
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-27
  • 1970-01-01
  • 2021-03-18
  • 2021-03-16
相关资源
最近更新 更多