Этот пост предназначен для людей, которые только начали работать с Rust и не совсем понимают, как работает заимствование и пожизненное использование.

TL; DR После того, как что-то было перемещено, оно исчезло. Только одна изменяемая ссылка за раз. Копирование может быть дорогостоящим, но иногда требуется.

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

Перечитывая некоторые главы книги Rust о заимствованиях и сроках жизни, я наконец понял это. Я попытаюсь объяснить свое мнение о том, как это работает. Может, тебе это тоже поможет.

Заимствование и переезд

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

fn main() {
    let foo = String::from("Hi");
    other_function(foo);
    // foo is now gone, the ownership was moved
}

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

использованная литература

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

fn main() {
    let foo = String::from("Hi");
    do_something(&foo);
    do_more(&foo);
}

Вы можете делать это так часто, как хотите. Единственное, на что вам нужно обратить внимание, - это изменяемые ссылки. Вы можете создавать только одну изменяемую ссылку за раз.

// you cannot do this
let mut foo = String::from("Hi");
let x = &mut foo;
let y = &foo;
// you cannot do this
let mut foo = String::from("Hi");
let x = &mut foo;
let y = &foo;
// but you can do this
let mut foo = String::from("Hi");
do_something(&mut foo);
do_more(&mut foo);

Последний работает, потому что функции будут вызываться одна за другой. Некогда существовало две ссылки.

Возврат ссылки

Иногда я пытался вернуть ссылку на переменную, созданную мной в той же области. Это, конечно, вызывает ошибку, поскольку вы не можете вернуть ссылку на то, чего больше не существует. Чтобы это сработало, вам нужно скопировать значение.

fn main() {
    let string1 = String::from("Hi");
    let string2 = String::from("Hello");
    let longer = longer_string(&string1, &string2);
    println!("Result: {:?}", longer);
}
fn longer_string(a: &String, b: &String) -> String {
    if a.len() > b.len() {
        a.clone()
    } else {
        b.clone()
    }
}

Это не вернет ссылку, а будет возвращено значение типа String, которое затем можно будет использовать в области, которая вызвала эту функцию.

Время жизни

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

fn main() {
    let foo = String::from("Hi");
    let c = first_letter(&foo);
    println!("{:?}", c);
}
fn first_letter<'a>(bar: &'a String) -> &'a str {
    return &bar[0..1];
}

Время жизни в этом примере не требуется, поскольку он прост и компилятор понимает простые вещи. Однако ключевым моментом здесь является то, что время жизни сообщает компилятору, что ссылки, используемые в этой функции, будут жить достаточно долго. В этом случае, пока ‘a.

fn main() {
    let string1 = String::from("Hi");
    {
        let string2 = String::from("Hello");
        let longer = longer_string(&string1, &string2);
        println!("Result: {:?}", longer);
    }
}
fn longer_string<'a>(a: &'a String, b: &'a String) -> &'a str {
    return if a.len() > b.len() { a } else { b };
}

Здесь Rust требует указания времени жизни. Аргументы поступают из двух разных областей, поэтому только самый короткий из них является допустимым временем жизни, которое может быть возвращено.

Вывод

Я пропустил некоторые части, чтобы сделать это кратко. Для получения дополнительной информации прочтите Книгу Rust или загляните в документацию.