#rust
#Ржавчина
Вопрос:
У меня есть функция, принимающая два заимствованных массива универсального типа T
, и я хотел бы создать HashSet
s из этих массивов, чтобы я мог их сравнить.
Я думал, что смогу сделать что-то вроде этого:
pub fn sublist<T: PartialEq>(first_list: amp;[T], second_list: amp;[T]) -> bool {
let first_set: HashSet<T> = first_list.iter().collect();
let second_set: HashSet<T> = second_list.iter().collect();
first_set.is_subset(amp;second_set)
}
Но в итоге я получаю следующие ошибки:
a value of type `std::collections::HashSet<T>` cannot be built from an iterator over elements of type `amp;T`
value of type `std::collections::HashSet<T>` cannot be built from `std::iter::Iterator<Item=amp;T>`
help: the trait `std::iter::FromIterator<amp;T>` is not implemented for `std::collections::HashSet<T>`
Из-за первой строки ошибки я подумал, что смогу решить ее следующим образом (я просто изменил тип hashset на ссылки amp;T
):
pub fn sublist<T: PartialEq>(first_list: amp;[T], second_list: amp;[T]) -> bool {
let first_set: HashSet<amp;T> = first_list.iter().collect();
let second_set: HashSet<amp;T> = second_list.iter().collect();
first_set.is_subset(amp;second_set)
}
Но затем я вижу эти ошибки:
the trait bound `T: std::cmp::Eq` is not satisfied
the trait `std::cmp::Eq` is not implemented for `T`
note: required because of the requirements on the impl of `std::cmp::Eq` for `amp;T`
note: required because of the requirements on the impl of `std::iter::FromIterator<amp;T>` for `std::collections::HashSet<amp;T>`
Я не понимаю, как создавать новые структуры данных из ссылок на массив. Проблема заключается в том, что эти массивы заимствованы, или, в конечном счете, проблема связана с PartialEq
этим признаком?
Что, если по какой-либо причине я не могу изменить сигнатуру функции, как я могу использовать hashsets для сравнения коллекций?
Комментарии:
1.
HashSet
требуетсяEq
,PartialEq
недостаточно. У вас также, вероятно, будет ошибка об отсутствии привязки признакаHash
, если вы этого еще не сделали.2. Это означает, что его невозможно использовать
HashSet
для сравнения этих массивов? Было бы идиоматично выполнять сравнение вручную или есть какая-то другая коллекция, которую я должен использовать?3. Rust требует, чтобы любая функциональность дженериков была объявлена заранее. Если
PartialEq
это все, с чем вам нужно работать, то вы не можете использовать какой-либо хешированный или упорядоченный контейнер, чтобы сделать проверку эффективной. Вы могли бы поместить их в aVec
, но если вы даже не можете их отсортировать (требуетсяOrd
), тогда зачем беспокоиться? Использование.contains
непосредственно в цикле — это действительно единственный вариант, который я вижу с заданными ограничениями.
Ответ №1:
Для использования HashSet
вашей функции необходимо иметь границы Eq
и Hash
признака:
use std::hash::Hash;
use std::collections::HashSet;
pub fn sublist<T: Eq Hash>(first_list: amp;[T], second_list: amp;[T]) -> bool {
let first_set: HashSet<amp;T> = first_list.iter().collect();
let second_set: HashSet<amp;T> = second_list.iter().collect();
first_set.is_subset(amp;second_set)
}
Если вы знаете только, что T
это PartialEq
так, вы можете реализовать это следующим образом:
pub fn sublist<T: PartialEq>(first_list: amp;[T], second_list: amp;[T]) -> bool {
first_list.iter().all(|v| second_list.contains(v))
}
Другие варианты включают T: Ord
и использование BTreeSet
.