Как эффективно сбросить все значения Vec <T>без изменения его размера? - PullRequest
1 голос
/ 13 мая 2019

Я могу использовать resize, но это кажется излишним, потому что мне не нужно изменять размер вектора, просто измените его значения. Использование новой переменной не вариант, так как этот вектор фактически является полем в структуре.

Я полагаю, что resize является эффективным и, вероятно, ответом на мой вопрос, но его название не несет смысла сброса значений без изменения размера.

В C я бы использовал memset (вместо realloc).

Иллюстрация моего вопроса:

let my_vec_size = 42;
let mut my_vec = Vec::new();       //  'my_vec' will always have a size of 42
my_vec.resize(my_vec_size, false); //  Set the size to 42, and all values to false

// [ ... ] piece of code where the values in 'my_vec' will be modified, checked, etc ...


// now I need to reuse my_vec.
// Possibility A -> use resize again
my_vec.resize(my_vec_size, false);

// Possibility B -> iterate on the vector to modify its values (long and laborious)
for item in my_vec.iter_mut() {
    *item = false;
}

// Possibility C ?

Ответы [ 3 ]

5 голосов
/ 13 мая 2019

Самый эффективный способ - сбросить сами значения (B):

for item in &mut my_vec { *item = false; }

Для логических значений это не сразу очевидно, однако для String важно сохранить выделенный буфер каждого элемента:

for item in &mut my_vec { item.clear(); }

Если отбрасывать и воссоздавать элементы Vec дешево, например, в случае логического значения или если элементы все равно будут перезаписаны, то комбинация clear и resize проще:

my_vec.clear();
my_vec.resize(my_vec_size, false);
2 голосов
/ 13 мая 2019

resize само по себе будет не работать для "сброса" значений:

const LEN: usize = 3;

fn main() {
    let mut values = vec![false; LEN];

    values[0] = true;

    values.resize(LEN, false);
    println!("{:?}", values); // [true, false, false]
}

Просто используйте цикл for:

for v in &mut values {
    *v = false;
}
println!("{:?}", values); // [false, false, false]

Если это зрелище оскорбляет вас, напишите черту расширения :

trait ResetExt<T: Copy> {
    fn reset(&mut self, val: T);
}

impl<T: Copy> ResetExt<T> for [T] {
    fn reset(&mut self, value: T) {
        for v in self {
            *v = value;
        }
    }
}
values.reset(false);
println!("{:?}", values); // [false, false, false]

Идея черты может быть расширена, так что каждое значение знает, как сбросить себя, если это имеет смысл дляваша ситуация:

trait ResetExt {
    fn reset(&mut self);
}

impl<T: ResetExt> ResetExt for [T] {
    fn reset(&mut self) {
        for v in self {
            v.reset();
        }
    }
}

impl ResetExt for bool {
    fn reset(&mut self) {
        *self = false;
    }
}

impl ResetExt for String {
    fn reset(&mut self) {
        self.clear();
    }
}
values.reset();
println!("{:?}", values); // [false, false, false]
0 голосов
/ 14 мая 2019

В C я бы использовал memset

std::ptr::write_bytes использует memset внутри, так что вы можете (почти) точно перевести этот код. Пример из документации по Rust:

let mut vec = vec![0u32; 4];
unsafe {
    let vec_ptr = vec.as_mut_ptr();
    ptr::write_bytes(vec_ptr, 0xfe, 2);
}
assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...