String types are comparable but not in hashmap

Hi. Please advise. Now I am writing tests and I am used to specifying a convenient &str instead of the String returned from functions.

However, when checking for hashmap, this does not work and requires an explicit match of string types.

Why is this not necessary for strings but is necessary for hashmap with strings?

1. mismatched types
   expected struct `std::collections::HashMap<std::string::String, {integer}>`
      found struct `std::collections::HashMap<&str, {integer}>` [E0308]
#[test]
    fn it_work() {
        assert_eq!("abc", "abc".to_string());
        assert_eq!(
            HashMap::from([("a".to_string(), 1)]),
            HashMap::from([("a", 1)])
        );
    }

&'a str implements PartialEq for String[1], so you can compare a string slice with a string directly. HashMap<&'a str, V> does not implement PartialEq for HashMap<String, V>, which makes them not comparable directly.


  1. And vice versa, but the implementation used in your example is the one from &'a str. ↩︎

1 Like

Hi! Thank you!
As I see it, in Rust it will not be correct to compare different types unless they belong to the same group. I hope I understood correctly.

assert_eq!(1u8, 1i8 as u8);
// wrong! assert_eq!(1u8, 1i8);

Most operators in Rust like == use traits under the hood. You can find these traits in std::ops or for comparison operators in std::cmp. The == operator uses the PartialEq trait. An expression lhs == rhs is basically syntactic sugar for calling <lhs as PartialEq<Rhs>>::eq(&rhs), where Rhs is the type of rhs. As long as you implement PartialEq<Rhs> for Lhs—the type of the lhs variable—, you can compare values of Lhs to values of Rhs, even when Lhs is not the same type as Rhs. Integer types in Rust only implement PartialEq<Self>, which means u8 instances are only comparable to other u8 instances, u16 instances to other u16 instances and so forth.

1 Like

Thanks for explaining how it works under the hood.

So, in principle, it can be implemented for tuples and hash tables and other data? It's just that these implementations are not yet in the standard library?

#[test]
    fn it_works() {
        //wrong! assert_eq!((1, "1", '1'), (1, "1".to_string(), '1'.to_string()));
        //wrong! assert_eq!(["1"], vec!["1"]);
        assert_eq!(["1"].as_slice(), vec!['1'.to_string(), "1".to_string()]);
        assert_eq!(vec!["1", "1"], ['1'.to_string(), "1".to_string()]);
    }

In the end, on the one hand, this will add flexibility, but for some people strictness is needed right down to the types.

I suppose there are crates for these requirements. Well, for the standard library, the idea of ​​flexibility without breaking logic is clearly closer.

Thanks again!

Strictly speaking, it's not that they are not yet in the standard library - I guess in a lot of cases they are impossible, or at least undesirable, to add to a standard library, due to ambiguities being created.

1 Like