【问题标题】:"my first rust": the method `unwrap_or_default` exists for enum `Option<&mut ...>`, but its trait bounds were not satisfied“我的第一次生锈”:枚举 `Option<&mut ...>` 存在方法 `unwrap_or_default`,但不满足其特征界限
【发布时间】:2021-07-13 20:50:27
【问题描述】:

我的第一个rust 程序/函数应该遍历目录树并提供HashMapK(mime_as_string)V(count_sum, size_sum)。我想要它的 FP 风格。

所以我拥有的是这样的:

fn files_info4(rootpath: &str) {

    struct FTypeStats {
        count: u64,
        size: u64,
    }

    impl Default for FTypeStats {
        fn default() -> Self {
            FTypeStats {
                count: 0,
                size: 0,
            }
        }
    }

    // get file type stats directly/functionally/lazy
    let fts = WalkDir::new(rootpath)
    .min_depth(1)
    .max_depth(99)
    .into_iter()
    .filter_map(|entry| entry.ok())
    .map(|entry| (entry, entry.metadata().map_or(false, |m| m.is_file())))
    .filter(|(e, f)| *f)
    .fold(HashMap::new(), | mut acc: HashMap<String, FTypeStats>, (e, _) | {
        let ftype = tree_magic::from_filepath(e.path());
        acc.get_mut(&ftype).unwrap_or_default().count += 1;
        acc.get_mut(&ftype).unwrap_or_default().size += e.metadata().map_or(0, |m| m.len());
        acc
    });
}

遇到错误后我在哪里做impl Default

error[E0599]: the method `unwrap_or_default` exists for enum `Option<&mut FTypeStats>`, but its trait bounds were not satisfied
  --> src/main.rs:54:29
   |
54 |         acc.get_mut(&ftype).unwrap_or_default().count += 1;
   |                             ^^^^^^^^^^^^^^^^^ method cannot be called on `Option<&mut FTypeStats>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `&mut FTypeStats: Default`

但它仍然没有帮助,即仍然存在相同的错误。

问题:

  1. 如何编译/运行
  2. 可以优化评估链吗? (fold 中的代码实际上是否正确,例如我需要为 FTypeStats 进行的分配和初始化默认/初始值?(感觉有点“隐含”))

TIA!

【问题讨论】:

    标签: rust functional-programming


    【解决方案1】:

    这里有多个问题:首先,在HashMap 上调用.get_mut() 会给您一个Option,即None,以防密钥不在地图中。 Option 本身与地图分离(除了生命周期约束),因此在None-case 中,没有链接返回到地图中,可以将默认构造的值放在适当的位置。

    其次,正如错误消息所说,方法unwrap_or_default()需要Option的内部类型才能实际实现Default,在本例中为&amp;mut FTypeStats。这样的实现不仅在您的代码中不存在,而且这样做也非常困难,因为凭空生成对某种类型的(有效)可变引用 - 这是Default 的重点 - 实际上是不可能的。

    解决方案是在HashMap 上使用entry() API 而不是get_mut()

    *acc.entry(&ftype).or_default().count += 1;
    

    entry() 的调用为您提供了一个代理值,指向&amp;ftype 位于或将位于HashMap 中的任何位置。对or_default() 的调用总是会给你一个&amp;mut FTypeStats。如果&amp;ftype 不在映射中,它使用Default on FTypeStats(不是Default on &amp;mut FTypeStats)生成一个新条目,插入它,并为您提供一个可变引用。

    【讨论】:

    • 谢谢,这让我更接近了,虽然我现在遇到了一个新问题:如果我的哈希键是一个值 (String) 我得到 使用移动值:ftype 我第二次索引(对于+size);如果我尝试通过使用引用(例如&amp;str)作为键来解决这个问题,我会得到(对于两个索引)ftype 的寿命不够长。如果我尝试通过为FTypeStats 实现add 并像这样添加acc.entry(ftype).or_default().add(FTypeStats{count: 1, size: e.metadata().map_or(0, |m| m.len())}); 来解决那个(天真?),它会运行但所有值都是0。 (而且比我的go 版本慢很多)
    猜你喜欢
    • 2022-01-20
    • 2021-01-17
    • 2019-10-11
    • 1970-01-01
    • 2022-11-27
    • 2021-04-20
    • 2021-08-23
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多