Qual é a maneira correta de indexar em um HashMap<&String, V>
com um &str
? Rust relata que &String
não é Borrow<str>
, o que é necessário para indexação. (Isso parece um pouco bobo para mim; se T: Borrow<U>
então certamente &T: Borrow<U>
também deveria ser válido?)
use std::collections::HashMap;
fn main() {
let strings = vec!["x".to_owned(), "y".to_owned(), "z".to_owned()];
let m = [0, 1, 2]
.into_iter()
.map(|i| (&strings[i], i))
.collect::<HashMap<&String, usize>>();
let zero = m["x"];
}
error[E0277]: the trait bound `&String: Borrow<str>` is not satisfied
--> src/main.rs:9:18
|
9 | let zero = m["x"];
| ^^^ the trait `Borrow<str>` is not implemented for `&String`, which is required by `HashMap<&String, usize>: Index<&_>`
|
= help: the trait `Borrow<str>` is implemented for `String`
= help: for that trait implementation, expected `String`, found `&String`
= note: required for `HashMap<&String, usize>` to implement `Index<&str>`
Obviamente, como eu construí esse HashMap em particular, eu poderia voltar e mudar seu tipo de chave para &str
em vez disso. Mas supondo que eu receba um HashMap<&String, V>
, qual é a maneira correta de indexá-lo? Construir um whole String
apenas para pegar uma referência a ele parece desperdício.
Existe uma maneira de contornar isso se você estiver disposto a mergulhar em águas perigosas.
Esta solução aproveita o fato de que se você tiver uma struct
S
marcada#[repr(transparent)]
e contendo um único campo do tipoT
, você pode transmutar com segurança de&'a T
para&'b S
onde'a: 'b
. (É por isso que você pode pegar emprestado a&Path
de aPathBuf
mesmo que nenhumPath
nunca exista de fato , por exemplo.)Então, vamos construir um novo tipo que podemos pegar emprestado de
String
, e com um nome positivamente bikesheddable.Essa definição nos permite transmutar com segurança de
&str
para&StrRef
, então vamos encapsular esse pedaço de código inseguro em umaFrom
implementação:Agora podemos implementar
Borrow<StrRef>
em qualquer tipo do qual podemos obter um&str
.Por fim, isso nos permite escrever a seguinte função, que realiza seu objetivo de buscar no mapa usando um
&str
sem convertê-lo em um ownedString
:( Parque infantil )
Obviamente, se você puder alterar o tipo de chave do mapa,
&str
então você deve preferir isso, mas se você não tem controle sobre a origem do mapa, então esta é uma solução viável (em um escopo -- esperançosamente -- muito limitado dentro do seu programa).conflitos com o existente
então não pode ser adicionado.
Parque infantil
Quando você está no controle, você não deve usar
&String
como chaves para começar. A maneira preferida seria usar&str
que pode ser trivialmente criado a partir de a&String
e você não tem o problema e é mais geral.Quando você não está no controle, criar um
String
índice justo é sua única opção segura.