Как я могу (срезать) сопоставление с шаблоном на принадлежащем Ve c элементах без копирования? - PullRequest
1 голос
/ 28 мая 2020

Моя цель - переместить элементы из принадлежащего Vec.

fn f<F>(x: Vec<F>) -> F {
    match x.as_slice() {
        &[a, b] => a,
        _ => panic!(),
    }
}

Если F является копией, это не проблема, так как можно просто скопировать из фрагмента. Когда F не является, шаблоны срезов кажутся не- go, поскольку срез доступен только для чтения. , чтобы переместить элементы из x?

Изменить: Теперь я вижу, что этот код имеет более общую проблему. Функция

fn f<T>(x: Vec<T>) -> T {
    x[0]
}

оставляет «дыру в Vec», даже если она сразу после этого отбрасывается. Это не разрешено. Этот пост и это обсуждение описывают эту проблему.

Это приводит к обновленному вопросу: как можно правильно использовать Vec<T> для сопоставления с образцом?

Ответы [ 3 ]

2 голосов
/ 28 мая 2020

Вы не можете использовать сопоставление шаблонов с образцами срезов в этом сценарии.

Как вы правильно отметили при редактировании вашего вопроса, перемещение значения из Vec оставляет его с неинициализированной памятью. Это может затем вызвать Undefined Behavior, когда Vec впоследствии будет удален, потому что его реализация Drop должна освободить память кучи и, возможно, удалить каждый элемент.

В настоящее время нет способа express, который ваш параметр типа F не имеет реализации Drop или что его можно безопасно вызвать из неинициализированной памяти.

Вы в значительной степени должны забыть об использовании шаблона среза и записать его более подробно:

fn f<F>(mut x: Vec<F>) -> F {
    x.drain(..).next().unwrap()
}

Если вы полностью настроены на сопоставление с образцом, вы можете вместо этого использовать Itertools::tuples() для сопоставления с кортежами:

use itertools::Itertools; // 0.9.0

fn f<F>(mut x: Vec<F>) -> F {
    match x.drain(..).tuples().next() {
        Some((a, _)) => a,
        None => panic!()
    }
}
1 голос
/ 28 мая 2020

Если вы настаиваете на сопоставлении с образцом, вы можете сделать это:

fn f<F>(x: Vec<F>) -> F {
    let mut it = x.into_iter();
    match (it.next(), it.next(), it.next()) {
        (Some(x0), Some(_x1), None) => x0,
        _ => panic!(),
    }
}

Однако, если вы просто хотите получить первый элемент двухэлементного вектора (паника в других случаях), я думаю Я бы предпочел go с этим:

fn f<F>(x: Vec<F>) -> F {
    assert_eq!(x.len(), 2);
    x.into_iter().next().unwrap()
}
1 голос
/ 28 мая 2020

Один из способов добиться использования одного элемента вектора - заменить последний элемент тем элементом, который вы хотите использовать, а затем вытолкнуть последний элемент

fn f<F>(mut x: Vec<F>) -> F {
    match x.as_slice() {
        [_a, _b] => {
            x.swap(0, 1);
            x.pop().unwrap() // returns a
        },
        _ => panic!(),
    }
}

В коде используется unwrap что не изящно.

...