昨天提到了生命週期的標記,今天我們就來看一下該怎麼手動標記生命週期
生命週期的標記長這樣 '
+ 單字或者字母
大部分的人都會用 'a
來表示
我們先來解決昨天最後一個範例錯誤
> cargo run
error[E0106]: missing lifetime specifier
--> src/main.rs:9:38
|
9 | fn introduction(a: &i32, b: &i32) -> &i32 {
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
help: consider introducing a named lifetime parameter
|
9 | fn introduction<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
| ++++ ++ ++ ++
For more information about this error, try `rustc --explain E0106`.
error: could not compile `hello_world` (bin "hello_world") due to previous error
其實錯誤訊息就有提示我們該怎麼加生命週期標記
我們來看一下
a 跟 b 在借用標記後面加上 'a
代表著他要活得跟 'a
一樣久
不過我們都不知道 'a
會活多久
我們來把生命週期加上去吧
當我們要在函式中使用生命週期標記時,需要加上 <'a>
表示聲明的意思
我們在返回值也會加上 'a
表示返回值的生命週期與參數們一樣,
這樣就不需要擔心無效的指向
fn main() {
let number1 = 1;
let number2 = 2;
let result = introduction(&number1, &number2);
println!("{:?}", result)
}
fn introduction<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
if a > b {
a
} else {
b
}
}
所以說, 'a
到底能活多久?這個需要依據裡面的參數而定
當我們在 Function 聲明使用生命週期的時候,
'a
的生命週期範圍就會是參數之間重疊的區域,
也就是說,'a
的生命週期與生命週期短的參數一樣,
我們直接用上面的例子來看好了
在 introduction
兩個參數的作用域在於 main
這個 Function 中,所以兩個的生命週期是一樣的
那如果我們把 number2
以及 introduction
這個 Function 放到一個 block 中呢?
fn main() {
let number1 = 1;
let result;
{
let number2 = 2;
result = introduction(&number1, &number2);
}
println!("{:?}", result)
}
fn introduction<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
if a > b {
a
} else {
b
}
}
即便我們給他生命週期的標記,但在編譯的時候還是會出錯,為什麼呢?
> cargo run
error[E0597]: `number2` does not live long enough
--> src/main.rs:7:41
|
6 | let number2 = 2;
| ------- binding `number2` declared here
7 | result = introduction(&number1, &number2);
| ^^^^^^^^ borrowed value does not live long enough
8 | }
| - `number2` dropped here while still borrowed
9 |
10 | println!("{:?}", result)
| ------ borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `hello_world` (bin "hello_world") due to previous error
剛剛有說到 'a
的生命週期取決於兩個參數重疊的作用域,
也就是說會以作用域小的為主
在上述的例子 'a
的作用域會跟 number2
相同,生命週期也相同
一旦出了 block 'a
與 number2
就不在了,
但其實他們應該要活到 println!
這裡
否則 result
就會指向無效的值
要怎麼解決呢?
可以把 number2
與 introduction
的 block 拿掉,
或者不要以借用的方式使用參數
如果希望參數之間的生命週期不一樣呢?我們可以使用多個生命週期
fn main() {
let number1 = 1;
let number2 = 2;
let result = introduction(&number1, &number2);
println!("{:?}", result)
}
fn introduction<'a, 'b>(a: &'a i32, b: &'b i32) -> &'a i32 {
if a > b {
a
} else {
b
}
}
不過這樣會編譯失敗,因為 Rust 無法確定返回值會借用哪個參數,
這個錯誤訊息在說 'b
可能會活得不夠久
如果返回值借用到 b 這個參數,可能就會壞掉
> cargo run
error: lifetime may not live long enough
--> src/main.rs:13:9
|
9 | fn introduction<'a, 'b>(a: &'a i32, b: &'b i32) -> &'a i32 {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
13 | b
| ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`
error: could not compile `hello_world` (bin "hello_world") due to previous error
所以我們需要給 b 一點強心針,讓 'b
活得跟 'a
一樣久
fn main() {
let number1 = 1;
let number2 = 2;
let result = introduction(&number1, &number2);
println!("{:?}", result)
}
fn introduction<'a, 'b: 'a>(a: &'a i32, b: &'b i32) -> &'a i32 {
if a > b {
a
} else {
b
}
}
> cargo run
2