Как передать один Vec нескольким функциям в Rust?

Я написал max функцию, которая принимает Vec в качестве параметра. Работает, как я и ожидал. Затем я добавил функцию min, аналогичную функции max:

fn main() {
    let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
    let max = max(my_array);
    let min = min(my_array);
    println!("Max value is {}.", max);
}

fn max(array: Vec<i32>) -> i32 {
    let mut max = array[0];
    for val in array {
        if max < val {
            max = val;
        }
    }
    max
}

fn min(array: Vec<i32>) -> i32 {
    let mut min = array[0];
    for val in array {
        if min > val {
            min = val;
        }
    }
    min
}

Rust сообщает об ошибке, если я использую тот же параметр my_array для вызова min:

error[E0382]: use of moved value: `my_array`
 --> src/main.rs:4:19
  |
2 |     let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
  |         -------- move occurs because `my_array` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 |     let max = max(my_array);
  |                   -------- value moved here
4 |     let min = min(my_array);
  |                   ^^^^^^^^ value used here after move

Как мне написать работающий код?


person tajihiro    schedule 22.03.2017    source источник
comment
Рекомендуем вам прочитать о семантике перемещения.   -  person E_net4 the curator    schedule 22.03.2017


Ответы (1)


Это проблема, с которой столкнутся даже новички в Rust. Новичку следует прочитать Язык программирования Rust . В эту книгу было вложено много усилий, особенно для новичков в Rust. Это коснется многих вещей, с которыми вы столкнетесь.

Соответствующие разделы:


Основная проблема заключается в том, что вы передали право собственности на вектор при вызове max. Затем значение исчезает; main его больше нет.

Самый простой способ - это клонировать вектор перед переходом к max. Это позволяет main сохранить право собственности на my_array, а затем передать право владения min в следующей строке:

let max = max(my_array.clone());
let min = min(my_array);

Это неэффективно, поскольку ни max, ни min не должны брать на себя ответственность за вектор, чтобы выполнять свою работу. Клонирование Vec также требует выделения дополнительной памяти. Более идиоматично передать срез, который является типом ссылки на данные внутри Vec:

let max = max(&my_array);
let min = min(&my_array);
fn max(array: &[i32]) -> i32 {
    let mut max = array[0];
    for &val in array {
        if max < val {
            max = val;
        }
    }
    max
}

При итерации по срезу вы возвращаете ссылки на элементы в срезе. С помощью целых чисел мы можем разыменовать их (здесь используется & в for &val in array) и сделать копию значения.

Смотрите также:


Более того, нет необходимости переписывать такие базовые функции. Вы также предполагаете, что всегда есть хотя бы одно значение, что неверно для пустого вектора. Идиоматическое решение - использовать итераторы:

fn main() {
    let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
    let max = my_array.iter().max();
    let min = my_array.iter().min();
    println!("Max value is {:?}.", max);
    println!("Min value is {:?}.", min);
}

Здесь используются Iterator::min и _ 18_, каждый из которых возвращает _ 19_, поскольку пустой фрагмент не имеет минимального или максимального значения.

Технически это немного отличается от вашего исходного решения, поскольку min и max равны Option<&i32>; ссылка на исходный фрагмент. Вы можете вернуться к Option<i32>, используя _24 _:

fn main() {
    let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
    let max = my_array.iter().max().copied();
    let min = my_array.iter().min().copied();
    println!("Max value is {:?}.", max);
    println!("Min value is {:?}.", min);
}

Дополнительная информация: срезы, Vec и массивы бывают разных типов. Было бы неправильно называть my_array массивом.

person Shepmaster    schedule 22.03.2017