0
点赞
收藏
分享

微信扫一扫

rust 生命周期

生命周期基础

编译器通过生命周期来确保所有的借用都是合法的,典型的,一个变量在创建时生命周期随之开始,销毁

时生命周期也随之结束。

生命周期的范围

1. 🌟

/* 为 `i` 和 `borrow2` 标 注 合 适 的 生 命 周 期 范 围 */

// `i` 拥 有 最 长 的 生 命 周 期 , 因 为 它 的 作 用 域 完 整 的 包 含 了 `borrow1` 和 `borrow2` 。

// 而 `borrow1` 和 `borrow2` 的 生 命 周 期 并 无 关 联 , 因 为 它 们 的 作 用 域 没 有 重 叠

fn main() {

let i = 3;

{

let borrow1 = &i; // `borrow1` 生 命 周 期 开 始. ──┐

// │

println!("borrow1: {}", borrow1); // │

} // `borrow1` 生 命 周 期 结 束. ──────────────────────────────────┘

{

let borrow2 = &i;

println!("borrow2: {}", borrow2);

}

}

2. 🌟🌟

示例

{

let x = 5; // ----------+-- 'b

// |

let r = &x; // --+-- 'a |

// | |

println!("r: {}", r); // | |

// --+ |

} // ----------+

/* 像 上 面 的 示 例 一 样 , 为 `r` 和 `x` 标 准 生 命 周 期 , 然 后 从 生 命 周 期 的 角 度. */

fn main() {

{

let r; // ---------+-- 'a

// |

{ // |

let x = 5; // -+-- 'b |

r = &x; // | |

} // -+ |

// |

println!("r: {}", r); // |

} // ---------+

}

生命周期标注

Rust 的借用检查器使用显式的生命周期标注来确定一个引用的合法范围。但是对于用户来说,我们在大多

数场景下,都无需手动去标注生命周期,原因是编译器会在某些情况下自动应用生命周期消除规则。

在了解编译器使用哪些规则帮我们消除生命周期之前,首先还是需要知道该如何手动标记生命周期。

函数

大家先忽略生命周期消除规则,让我们看看,函数签名中的生命周期有哪些限制:

需要为每个引用标注上合适的生命周期

返回值中的引用,它的生命周期要么跟某个引用参数相同,要么是 'static

示例

// 引 用 参 数 中 的 生 命 周 期 'a 至 少 要 跟 函 数 活 得 一 样 久

fn print_one<'a>(x: &'a i32) {

println!("`print_one`: x is {}", x);

}

// 可 变 引 用 依 然 需 要 标 准 生 命 周 期

fn add_one<'a>(x: &'a mut i32) {

*x += 1;

}

// 下 面 代 码 中 , 每 个 参 数 都 拥 有 自 己 独 立 的 生 命 周 期 , 事 实 上 , 这 个 例 子 足 够 简 单 , 因 此 它 们 应 该 被

fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {

println!("`print_multi`: x is {}, y is {}", x, y);

}

// 返 回 一 个 通 过 参 数 传 入 的 引 用 是 很 常 见 的 , 但 是 这 种 情 况 下 需 要 标 注 上 正 确 的 生 命 周 期

fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x }

fn main() {

let x = 7;

let y = 9;

print_one(&x);

print_multi(&x, &y);

let z = pass_x(&x, &y);

print_one(z);

let mut t = 3;

add_one(&mut t);

print_one(&t);

}

3. 🌟

/* 添 加 合 适 的 生 命 周 期 标 注 , 让 下 面 的 代 码 工 作 */

fn longest(x: &str, y: &str) -> &str {

if x.len() > y.len() {

x

} else {

y

}

}

fn main() {}

4. 🌟🌟🌟

/* 使 用 三 种 方 法 修 复 下 面 的 错 误 */

fn invalid_output<'a>() -> &'a String {

&String::from("foo")

}

fn main() {

}

5. 🌟🌟

// `print_refs` 有 两 个 引 用 参 数 , 它 们 的 生 命 周 期 `'a` 和 `'b` 至 少 得 跟 函 数 活 得 一 样 久

fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {

println!("x is {} and y is {}", x, y);

}

/* 让 下 面 的 代 码 工 作 */

fn failed_borrow<'a>() {

let _x = 12;

// ERROR: `_x` 活 得 不 够 久does not live long enough

let y: &'a i32 = &_x;

// 在 函 数 内 使 用 `'a` 将 会 报 错 , 原 因 是 `&_x` 的 生 命 周 期 显 然 比 `'a` 要 小

// 你 不 能 将 一 个 小 的 生 命 周 期 强 转 成 大 的

}

fn main() {

let (four, nine) = (4, 9);

print_refs(&four, &nine);

// 这 里 ,four 和 nice 的 生 命 周 期 必 须 要 比 函 数 print_refs 长

failed_borrow();

// `failed_borrow` 没 有 传 入 任 何 引 用 去 限 制 生 命 周 期 `'a`, 因 此 , 此 时 的 `'a` 生 命 周 期 是

}

Structs

6. 🌟

/* 增 加 合 适 的 生 命 周 期 标 准 , 让 代 码 工 作 */

// `i32` 的 引 用 必 须 比 `Borrowed` 活 得 更 久

#[derive(Debug)]

struct Borrowed(&i32);

// 类 似 的 , 下 面 两 个 引 用 也 必 须 比 结 构 体 `NamedBorrowed` 活 得 更 久

#[derive(Debug)]

struct NamedBorrowed {

x: &i32,

y: &i32,

}

#[derive(Debug)]

enum Either {

Num(i32),

Ref(&i32),

}

fn main() {

let x = 18;

let y = 15;

let single = Borrowed(&x);

let double = NamedBorrowed { x: &x, y: &y };

let reference = Either::Ref(&x);

let number = Either::Num(y);

println!("x is borrowed in {:?}", single);

println!("x and y are borrowed in {:?}", double);

println!("x is borrowed in {:?}", reference);

println!("y is *not* borrowed in {:?}", number);

}

7. 🌟🌟

/* 让 代 码 工 作 */

#[derive(Debug)]

struct NoCopyType {}

#[derive(Debug)]

struct Example<'a, 'b> {

a: &'a u32,

b: &'b NoCopyType

}

fn main()

{

let var_a = 35;

let example: Example;

{

let var_b = NoCopyType {};

/* 修 复 错 误 */

example = Example { a: &var_a, b: &var_b };

}

println!("(Success!) {:?}", example);

}

8. 🌟🌟

#[derive(Debug)]

struct NoCopyType {}

#[derive(Debug)]

#[allow(dead_code)]

struct Example<'a, 'b> {

a: &'a u32,

b: &'b NoCopyType

}

/* 修 复 函 数 的 签 名 */

fn fix_me(foo: &Example) -> &NoCopyType

{ foo.b }

fn main()

{

let no_copy = NoCopyType {};

let example = Example { a: &1, b: &no_copy };

fix_me(&example);

println!("Success!")

}

举报

相关推荐

0 条评论