哈希映射宏拒绝类型检查,失败并显示误导性(并且看似有缺陷)的错误消息? [英] Hash map macro refuses to type-check, failing with a misleading (and seemingly buggy) error message?

查看:28
本文介绍了哈希映射宏拒绝类型检查,失败并显示误导性(并且看似有缺陷)的错误消息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里有这两个相关的宏:

I've got these two related macros here:

#[macro_export]
macro_rules! hash_map {
    ( $( $key:expr => $value:expr ),* ) => {
        {
            use ::std::iter::FromIterator;
            ::std::collections::HashMap::from_iter(&[$(($key, $value)),*])
        }
    };
}

#[macro_export]
macro_rules! hash_set {
    ( $( $x:expr ),* ) => {
        {
            use ::std::iter::FromIterator;
            ::std::collections::HashSet::from_iter(&[$($x),*])
        }
    };
}

我主要在测试中使用它,就像这样:

I'm primarily using it in tests, like this:

assert!(foo.one == hash_map!{});
assert!(foo.two == hash_set![String::from("some value")]);

但出于某种原因,我收到了一条非常具有误导性和荒谬的错误消息:

But for some reason, I'm getting a very misleading and nonsensical error message out of it:

error[E0271]: type mismatch resolving `<&[_; 0] as std::iter::IntoIterator>::Item == (_, _)`
   --> src/common.rs:M:N
    |
6   |             ::std::collections::HashMap::from_iter(&[$(($key, $value)),*])
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
    | 
   ::: src/foo.rs:M:N
    |
154 |         assert!(foo.one == hash_map!{});
    |                                         ----------- in this macro invocation
    |
    = note: expected type `&_`
               found type `(_, _)`
    = note: required by `std::iter::FromIterator::from_iter`

error[E0308]: mismatched types
   --> src/common.rs:M:N
    |
16  |             ::std::collections::HashSet::from_iter(&[$($x),*])
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found reference
    | 
   ::: src/foo.rs:M:N
    |
150 |     fn it_can_do_things() {
    |                                - help: try adding a return type: `-> std::collections::HashSet<&std::string::String, _>`...
155 |         assert!(foo.two == hash_set![String::from("some value")]);
    |                                  -------------------------------------------- in this macro invocation
    |
    = note: expected type `std::collections::HashSet<std::string::String, std::collections::hash_map::RandomState>`
               found type `std::collections::HashSet<std::string::String, std::collections::hash_map::RandomState>`
               found type `std::collections::HashSet<&std::string::String, _>`

我曾尝试将元组本身作为第一个引用,但这没有帮助.

I've tried making the tuple a reference itself for the first, but that didn't help.

error[E0271]: type mismatch resolving `<&[_; 0] as std::iter::IntoIterator>::Item == (_, _)`
   --> src/common.rs:M:N
    |
6   |             ::std::collections::HashMap::from_iter(&[$(&($key, $value)),*])
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
    | 
   ::: src/foo.rs:M:N
    |
154 |         assert!(foo.one == hash_map!{});
    |                                         ----------- in this macro invocation
    |
    = note: expected type `&_`
               found type `(_, _)`
    = note: required by `std::iter::FromIterator::from_iter`

我的目标是尝试让哈希映射保留并在一个批次中添加所有内容,但我无法使其正常工作.请注意,我正在创建的哈希映射/集拥有其值.

My goal is to try to get the hash map to reserve and add everything in a single batch, but I just can't get it to work correctly. Note that the hash map/set I'm creating owns its values.

推荐答案

最小化复制:

fn main() {
    use std::collections::HashMap;
    use std::iter::FromIterator;

    let _ = HashMap::from_iter([("key", "value")].iter());
}

您必须迭代拥有的元组,而不是借用的元组,因此出现奇怪的错误消息:

You must iterate over owned tuples, not borrowed, hence the strange error message:

fn main() {
    use std::collections::HashMap;
    use std::iter::FromIterator;

    let _: HashMap<_, _> = HashMap::from_iter([("key", "value")].iter().cloned());
}

您也可以使用 collect,如 FromIterator 的文档中所述:

You can also use collect as said in the documentation of FromIterator:

FromIteratorfrom_iter 很少被显式调用,而是通过 Iteratorcollect 方法使用.有关更多示例,请参阅 collect 的文档.

FromIterator's from_iter is rarely called explicitly, and is instead used through Iterator's collect method. See collect's documentation for more examples.

fn main() {
    use std::collections::HashMap;

    let _: HashMap<_, _> = [("key", "value")].iter().cloned().collect();
    // or
    let _: HashMap<_, _> = vec![("key", "value")].into_iter().collect();
}

<小时>

请注意,使用 collect 更容易理解错误信息:


Note that the error message is more understandable with collect:

error[E0277]: the trait bound `std::collections::HashMap<_, _>: std::iter::FromIterator<&(&str, &str)>` is not satisfied
 --> src/main.rs:4:54
  |
4 |     let _: HashMap<_, _> = [("key", "value")].iter().collect();
  |                                                      ^^^^^^^ a collection of type `std::collections::HashMap<_, _>` cannot be built from an iterator over elements of type `&(&str, &str)`
  |
  = help: the trait `std::iter::FromIterator<&(&str, &str)>` is not implemented for `std::collections::HashMap<_, _>`

最后一行更有帮助:迭代器必须迭代元组而不是对元组的引用:

The last line is the more helpful: the iterator must iterate over tuples and not references to tuples:

impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S> 

这篇关于哈希映射宏拒绝类型检查,失败并显示误导性(并且看似有缺陷)的错误消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆