Вот минимальный код, необходимый для воспроизведения проблемы:
fn f1(s: &String) -> usize { unimplemented!() }
fn f2(s: &String) -> &str { unimplemented!() }
fn main() {
let mut s = String::from("some_string");
let n = f1(&s);
s.clear();
println!("n = {}", n);
}
Анализ времени жизни выполняется на основе сигнатур функций.
Вы заметитев приведенном выше коде, который я использовал unimplemented!()
в качестве тела функций, и проблема точно такая же.Это normal .
В подавляющем большинстве случаев 1 сигнатура функции полностью определяет интерфейс функции, и нет необходимости смотреть на ее реализацию.
Как следствие, это также означает, что ли время жизни в возвращаемом типе связано с временем жизни в любом из аргументов, полностью указано в сигнатуре, и в этом случае полная сигнатура f2
поэтому:
fn f2<'a>(s: &'a String) -> &'a str;
не имеет значения, является ли реализация f2
"def"
(со временем жизни 'static
) или &*s
(со временем жизни 'a
);только подпись имеет значение, и подпись использует тот же срок жизни из-за правил elision.
1 Единственное известное мне исключение касается функции -> impl Trait
и того, является лиобъект реализует Send
или Sync
.
В случае f1
тип возвращаемого значения не связан с аргументом, поэтому заимствование аргумента заканчивается в концевызова f1
:
fn main() {
let mut s = String::from("some_string");
let n = {
// Immutable borrow of s starts here.
f1(&s)
// Immutable borrow of s ends here.
};
s.clear();
println!("n = {}", n);
}
В случае f2
тип возвращаемого значения имеет то же время жизни, что и аргумент, и поэтому считается, что он расширяет заимствование.В Rust 2015 заем будет продлен до тех пор, пока возвращаемая стоимость не выйдет за рамки (лексический заем);с Rust 2018 заем продолжается до последнего использования возвращаемого значения (не лексический заем).
В вашем случае оба в основном идентичны:
fn main() {
let mut s = String::from("some_string");
let n = {
// Immutable borrow of s starts here.
f2(&s)
};
s.clear(); // Conflicting attempt to mutably borrow s.
println!("n = {}", n);
// Immutable borrow of s ends here.
}
Вы могли наблюдатьРазница путем переключения порядка s.clear()
и println!
.