Если выражения, которые дают либо значение, либо ссылку? - PullRequest
3 голосов
/ 25 октября 2019

У меня есть этот шаблон, который время от времени появляется, но я не нашел хорошего способа реализовать его "правильно".

Что это, у меня есть некоторая переменная, переданная в мою функциюпо ссылке. Мне не нужно изменять его, мне не нужно передавать право собственности, я просто смотрю на его содержимое.

Однако, если содержимое находится в каком-либо состоянии, замените значение значением по умолчанию.

Например, скажем, моя функция принимает &Vec<String>, а если vec пуст, замените его на vec!["empty"]. Кто-то может реализовать это так:

fn accept(mut vec: &Vec<String>) {
    if vec.len() == 0 {
        vec = &vec!["empty".to_string()];
    }
    // ... do something with `vec`, like looping over it
}

Но это дает ошибку:

| fn accept(mut vec: &Vec<String>) {
|                    - let's call the lifetime of this reference `'1`
|     if vec.len() == 0 {
|         vec = &vec!["empty".to_string()];
|         -------^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|         |      |
|         |      creates a temporary which is freed while still in use
|         assignment requires that borrow lasts for `'1`

Несколько более «хорошо продуманная» функция может выглядеть следующим образом (предотвращая mut):

fn accept(input: &Vec<String>) {
    let vec = if input.len() == 0 {
        &vec!["empty".to_string()]
    } else {
        input
    };
    // ... do something with `vec`, like looping over it
}

Однако это все равно приводит к той же ошибке, что и в предыдущем примере.

Единственное решение, которое я нашел, - это извлечь значение по умолчанию за пределы ifи просто сослаться на значение:

fn accept(input: &Vec<String>) {
    let default = vec!["empty".to_string()];
    let vec = if input.len() == 0 {
        &default
    } else {
        input
    };
    // ... do something with `vec`
}

Однако это приводит к менее чистому коду и также излишнему выполнению этого вычисления .

Я знаю и понимаю ошибку .. Вы заимствуете значение по умолчанию внутри тела if, но это значение, от которого вы заимствуете, не существует вне if. Это не мой вопрос.

Мой вопрос: есть ли более чистый способ выписать этот шаблон?

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

Ответы [ 2 ]

5 голосов
/ 25 октября 2019

Вам не нужно создавать вектор по умолчанию, если вы его не используете. Вы просто должны убедиться, что объявление сделано вне блока if.

fn accept(input: &Vec<String>) {
    let def;
    let vec = if input.is_empty() {
        def = vec!["empty".to_string()];
        &def
    } else {
        input
    };
    // ... do something with `vec`
}

Обратите внимание, что вам не нужно создавать новый вектор по умолчанию каждый раз, когда вы получаете пустой. Вы можете создать его в первый раз, когда это произойдет, используя lazy_static или once_cell:

#[macro_use]
extern crate lazy_static;

fn accept(input: &[String]) {
    let vec = if input.is_empty() {
        lazy_static! {
            static ref DEFAULT: Vec<String> = vec!["empty".to_string()];
        }
        &DEFAULT
    } else {
        input
    };
    // use vec
}
0 голосов
/ 26 октября 2019

Звучит так, будто вы ищете std::borrow::Cow, в зависимости от того, как вы собираетесь его использовать: https://doc.rust -lang.org / std / loan / enum.Cow.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...