Создайте HashSet из вектора в Rust

Я хочу построить HashSet<u8> из Vec<u8>. Я бы хотел сделать это

  • в одной строке кода,
  • копирование данных только один раз,
  • используя только 2n память,

но единственное, что я могу скомпилировать, это кусок... мусора, который, я думаю, дважды копирует данные и использует память 3n.

fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
    let mut victim = vec.clone();
    let x: HashSet<u8> = victim.drain(..).collect();
    return x;
}

Я надеялся написать что-то простое, например:

fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
    return HashSet::from_iter(vec.iter());
}

но это не будет компилироваться:

error[E0308]: mismatched types
 --> <anon>:5:12
  |
5 |     return HashSet::from_iter(vec.iter());
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found &u8
  |
  = note: expected type `std::collections::HashSet<u8>`
  = note:    found type `std::collections::HashSet<&u8, _>`

.. и я действительно не понимаю сообщение об ошибке, возможно потому, что мне нужно RTFM.

Ответ 1

Поскольку операция не должна потреблять вектор¹, я думаю, что она не должна потреблять его. Это приводит только к дополнительному копированию в другом месте программы:

use std::collections::HashSet;
use std::iter::FromIterator;

fn hashset(data: &[u8]) -> HashSet<u8> {
    HashSet::from_iter(data.iter().cloned())
}

Назовите его как hashset(&v), где v - это Vec<u8> или другое, что приводит к срезу.

Конечно, есть и другие способы написать это, быть универсальным и тому подобное, но этот ответ придерживается только того, на чем я хотел бы остановиться.

Это основано на том, что тип элемента u8 - Copy, то есть он не имеет семантики владения.

Ответ 2

Следующее должно работать хорошо; он отвечает вашим требованиям:

use std::collections::HashSet;
use std::iter::FromIterator;

fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
    HashSet::from_iter(vec)
}

from_iter() работает с типами, реализующими IntoIterator, поэтому достаточно аргумента Vec.

Дополнительные замечания:

  • вам не нужно явно return результаты функции; вам нужно только опустить точку с запятой в последнем выражении в его теле

  • Я не уверен, какую версию Rust вы используете, но на текущий стабильный (1.12) to_iter() не существует

Ответ 3

Перемещение владения данными

let vec: Vec<usize> = vec![1, 2, 3, 4];
let hash_set: HashSet<usize> = vec.into_iter().collect();

Клонирование данных

let vec: Vec<usize> = vec![1, 2, 3, 4];
let hash_set: HashSet<usize> = vec.iter().cloned().collect();