-
Notifications
You must be signed in to change notification settings - Fork 1.1k
lifetime/basic #180
-
lifetime/basic
Learn Rust with Example, Exercise and real Practice, written with ❤️ by https://course.rs team
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 5 -
😄 3 -
🎉 5 -
❤️ 5 -
🚀 2
Replies: 19 comments 9 replies
-
第10题的longest函数中参数y的生命周期是可以消除的吧
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 2
-
可以
Beta Was this translation helpful? Give feedback.
All reactions
-
fn longest<'a>(x: &'a str, y: &str) -> &'a str
Beta Was this translation helpful? Give feedback.
All reactions
-
聪明呀
Beta Was this translation helpful? Give feedback.
All reactions
-
不过这时,在编译器的角度,y 被标注了什么生命周期呢?
Beta Was this translation helpful? Give feedback.
All reactions
-
第1题
/* 为 `i` 和 `borrow2` 标注合适的生命周期范围 */ // `i` 拥有最长的生命周期,因为它的作用域完整的包含了 `borrow1` 和 `borrow2` 。 // 而 `borrow1` 和 `borrow2` 的生命周期并无关联,因为它们的作用域没有重叠 fn main() { let i = 3; // `i`生命周期开始 ─────────────────────────────┐ { │ let borrow1 = &i; // `borrow1` 生命周期开始. ─────┐ │ // │ │ println!("borrow1: {}", borrow1); // │ │ } // `borrow1` 生命周期结束. ─────────────────────────┘ │ { │ let borrow2 = &i; // `borrow2`生命周期开始 ───┐ │ │ │ println!("borrow2: {}", borrow2); │ │ } // `borrow2`生命周期结束─┘ │ } // `i`生命周期结束 ────────────────────────────────────────┘
第2题
/* 像上面的示例一样,为 `r` 和 `x` 标准生命周期,然后从生命周期的角度. */ fn main() { { let r; // ---------+-- 'a // | { // | let x = 5; // -+-- 'b | r = &x; // | | } // -+ | // | println!("r: {}", r); // | } // ---------+ } // 引用的生命周期'a比被引用对象的生命周期'b长,因此编译错误。
第3题
/* 添加合适的生命周期标注,让下面的代码工作 */ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } fn main() {}
第4题
4.1 方法1
/* 使用三种方法修复下面的错误 */ fn invalid_output() -> String { String::from("foo") } fn main() { }
4.2 方法2
/* 使用三种方法修复下面的错误 */ fn invalid_output() -> &'static str { "foo" } fn main() { }
4.3 方法3
/* 使用三种方法修复下面的错误 */ fn invalid_output<'a>() -> &'a str { "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() { let _x = 12; // ERROR: `_x` 活得不够久does not live long enough let y: &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` 生命周期是没有任何限制的,它默认是 `'static` }
第6题
/* 增加合适的生命周期标准,让代码工作 */ // `i32` 的引用必须比 `Borrowed` 活得更久 #[derive(Debug)] struct Borrowed<'a>(&'a i32); // 类似的,下面两个引用也必须比结构体 `NamedBorrowed` 活得更久 #[derive(Debug)] struct NamedBorrowed<'a> { x: &'a i32, y: &'a i32, } #[derive(Debug)] enum Either<'a> { Num(i32), Ref(&'a 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<'a: 'b, 'b>(foo: &'a Example) -> &'b NoCopyType { foo.b } fn main() { let no_copy = NoCopyType {}; let example = Example { a: &1, b: &no_copy }; fix_me(&example); println!("Success!") }
第9题
/* 添加合适的生命周期让下面代码工作 */ struct ImportantExcerpt<'a> { part: &'a str, } impl<'a> ImportantExcerpt<'a> { fn level(&'a self) -> i32 { 3 } } fn main() {}
第10题
/* 移除所有可以消除的生命周期标注 */ fn nput(x: &i32) { println!("`annotated_input`: {}", x); } fn pass(x: &i32) -> &i32 { x } fn longest<'a>(x: &'a str, y: &str) -> &'a str { x } struct Owner(i32); impl Owner { fn add_one(&mut self) { self.0 += 1; } fn print(&self) { println!("`print`: {}", self.0); } } struct Person<'a> { age: u8, name: &'a str, } enum Either<'a> { Num(i32), Ref(&'a i32), } fn main() {}
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 5
-
第八题这样为什么也能过编译?虽然与答案不同,如果这样可以的话应该可以应用生命周期消除。。然而不标注生命周期的话无法过编译
/* 修复函数的签名 */ fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType { foo.b }
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
了解了,谢谢!
Beta Was this translation helpful? Give feedback.
All reactions
-
#[derive(Debug)] #[allow(dead_code)] struct Example<'a, 'b> { a: &'a u32, b: &'b NoCopyType }
因为这个struct声明的隐含条件实际上已经包括了`b的生命周期应该至少不小于结构体对象的生命周期长度
fn fix_me(foo: &Example) -> &NoCopyType { foo.b }
这个调用虽然看起来符合消除的第一个原则
但实际上foo自己有一个隐含的'a
生命周期(应该和结构体里&'a u32'
不同)(为了不混淆其实自己起个别的名字更好比如'z
)
所以foo.b的生命周期其实和结构体的'a
并不相同
因此下面这样写之所以能够成功,是因为在告诉编译器返回值的生命周期和结构体的生命周期一样,但像上面所描述的原因,它是不能被省略消除的。
/* 修复函数的签名 */ fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType { foo.b }
Beta Was this translation helpful? Give feedback.
All reactions
-
我是这样理解的:
答案的生命周期标注
fn fix_me<'a: 'b, 'b>(foo: &'a Example) -> &'b NoCopyType;
表示'b
小于等于'a
即可。而采用相等生命周期的标注
fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType;
则是答案的一种特化,即此时'b
与'a
相等。正如文中所说
消除规则不是万能的,若编译器不能确定某件事是正确时,会直接判为不正确,那么你还是需要手动标注生命周期
编译器无法确定你需要前者的通用标注还是后者的特化标注,因此编译器会直接判为不正确。
为啥是 'b
小于等于 'a
即可?我不是疑惑 'a: 'b
的含义,而是疑惑结构体里的成员不应该要比结构体死得更晚吗?'b
是结构体内成员的生命周期,应该要比结构体 'a
更大吧
Beta Was this translation helpful? Give feedback.
All reactions
-
我是这样理解的:
答案的生命周期标注
fn fix_me<'a: 'b, 'b>(foo: &'a Example) -> &'b NoCopyType;
表示'b
小于等于'a
即可。而采用相等生命周期的标注
fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType;
则是答案的一种特化,即此时'b
与'a
相等。为啥是
'b
小于等于'a
即可?我不是疑惑'a: 'b
的含义,而是疑惑结构体里的成员不应该要比结构体死得更晚吗?'b
是结构体内成员的生命周期,应该要比结构体'a
更大吧
哈哈,是的,我写错了,当时脑子懵逼了😂我那样理解也是不对的,我把它删了,省得误导别人。
我现在理解的是,不符合第一个原则,因为 foo: &Example
这个参数包含3个生命周期,即 foo: &'c Example<'a, 'b>
。
Beta Was this translation helpful? Give feedback.
All reactions
-
done.
Beta Was this translation helpful? Give feedback.
All reactions
-
第8题我是这样写的,通过了:
#[derive(Debug)] struct NoCopyType {} #[derive(Debug)] #[allow(dead_code)] struct Example<'a, 'b> { a: &'a u32, b: &'b NoCopyType } /* 修复函数的签名 */ fn fix_me<'a, 'b>(foo: &Example<'a, 'b>) -> &'b NoCopyType { foo.b } fn main() { let no_copy = NoCopyType {}; let example = Example { a: &1, b: &no_copy }; fix_me(&example); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
Beta Was this translation helpful? Give feedback.
All reactions
-
第8题这样改也不错的:
#[derive(Debug)] struct NoCopyType { } #[derive(Debug)] #[allow(dead_code)] struct Example<'a, 'b> { a: &'a u32, b: &'b NoCopyType } /* 修复函数的签名 */ fn fix_me<'b>(foo: &Example<'_, 'b>) -> &'b NoCopyType { foo.b } fn main() { let no_copy = NoCopyType {}; let example = Example { a: &1, b: &no_copy }; fix_me(&example); println!("Success!") }
Beta Was this translation helpful? Give feedback.
All reactions
-
第四题,可以简写,为了练习没有简写。应该是对的吧
/* 使用三种方法修复下面的错误 */ fn invalid_output1<'a>() -> String { String::from("foo") } fn invalid_output2<'a>(s: &'a str) -> &'a str { s } fn invalid_output3<'a>() -> &'static str { "foo" } fn main() { }
Beta Was this translation helpful? Give feedback.
All reactions
-
lala
Beta Was this translation helpful? Give feedback.
All reactions
-
done
Beta Was this translation helpful? Give feedback.
All reactions
-
第4题的另一种解法
#![feature(string_leak)] fn invalid_output() ->&'static str { String::from("foo").leak() }
Beta Was this translation helpful? Give feedback.
All reactions
-
这个解法有点偷懒的感觉,因为可能会造成内存泄露。不过跑过了,就分享一下,哈哈哈哈
Beta Was this translation helpful? Give feedback.
All reactions
-
1、讲真,我本来以为标注是在代码中插入'a
这个符号,结果发现编译器让我删掉......看半天没写出来,发现参考答案的意思是在代码中用注释"画"出来,类似这种:
fn main() { let i = 3; // Lifetime for `i` starts. ────────────────┐ // │ { // │ let borrow1 = &i; // `borrow1` lifetime starts. ──┐│ // ││ println!("borrow1: {}", borrow1); // ││ } // `borrow1 ends. ──────────────────────────────────┘│ // │ // │ { // │ let borrow2 = &i; // `borrow2` lifetime starts. ──┐│ // ││ println!("borrow2: {}", borrow2); // ││ } // `borrow2` ends. ─────────────────────────────────┘│ // │ } // Lifetime ends. ─────────────────────────────────────┘
发现是示例没好好看......2333
2、略
3、生命周期使用:
/* 添加合适的生命周期标注,让下面的代码工作 */ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } fn main() {}
4、
第一种,不要考虑生命周期
/* 使用三种方法修复下面的错误 */ fn invalid_output() -> String { String::from("foo") } fn main() { }
第二种,引入入参
/* 使用三种方法修复下面的错误 */ fn invalid_output<'a>(input:&'a mut String) -> &'a String { (*input)=String::from("foo"); input } fn main() { }
第三种,考虑使用'static
fn invalid_output() -> &'static str { "foo" } fn main() { }
5、函数内使用``a会报错,函数内变量的生命周期显然小于
'a`
// `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 = &_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` 生命周期是没有任何限制的,它默认是 `'static` }
6、结构体中的引用
/* 增加合适的生命周期标准,让代码工作 */ // `i32` 的引用必须比 `Borrowed` 活得更久 #[derive(Debug)] struct Borrowed<'a>(&'a i32); // 类似的,下面两个引用也必须比结构体 `NamedBorrowed` 活得更久 #[derive(Debug)] struct NamedBorrowed<'a>{ x: &'a i32, y: &'a i32, } #[derive(Debug)] enum Either<'a> { Num(i32), Ref(&'a 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); } //不可以在外面 println!("(Success!) {:?}", example);因为结构体引用的var_b在上一个}被消除了 }
8、
#[derive(Debug)] struct NoCopyType {} #[derive(Debug)] #[allow(dead_code)] struct Example<'a, 'b> { a: &'a u32, b: &'b NoCopyType } /* 修复函数的签名 */ fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType { foo.b } fn main() { let no_copy = NoCopyType {}; let example = Example { a: &1, b: &no_copy }; fix_me(&example); println!("Success!") }
9、带引用的结构体实现方法的写法
/* 添加合适的生命周期让下面代码工作 */ struct ImportantExcerpt<'a> { part: &'a str, } impl <'a>ImportantExcerpt<'a> { fn level(&self) -> i32 { 3 } } fn main() {}
10、
/* 移除所有可以消除的生命周期标注 */ fn nput(x: & i32) { println!("`annotated_input`: {}", x); } fn pass(x: & i32) -> &i32 { x } fn longest<'a,'b>(x: &'a str, y: &'b str) -> &'a str { x } struct Owner(i32); impl Owner { fn add_one(& mut self) { self.0 += 1; } fn print(& self) { println!("`print`: {}", self.0); } } struct Person<'a> { age: u8, name: &'a str, } enum Either<'a> { Num(i32), Ref(&'a i32), } fn main() {}
Beta Was this translation helpful? Give feedback.
All reactions
-
/* 使用三种方法修复下面的错误 */ fn invalid_output<'a>() -> &'a str { "foo" } fn main() { }
上面能够通过编译,是因为"foo": &str具有'static
Beta Was this translation helpful? Give feedback.
All reactions
-
done~~~
Beta Was this translation helpful? Give feedback.
All reactions
-
有的题就和脑筋急转弯一样,不看答案是真难想啊
Beta Was this translation helpful? Give feedback.
All reactions
-
第三题
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
第四题
fn invalid_output1() -> String { String::from("foo") } fn invalid_output2() -> &'static str { "foo" } fn invalid_output3<'a>(s: &'a mut String) -> &'a String { *s = String::from("foo"); s }
第五题
fn failed_borrow() { let _x = 12; let y: &i32 = &_x; }
第六题
/* 增加合适的生命周期标准,让代码工作 */ // `i32` 的引用必须比 `Borrowed` 活得更久 #[derive(Debug)] struct Borrowed<'a>(&'a i32); // 类似的,下面两个引用也必须比结构体 `NamedBorrowed` 活得更久 #[derive(Debug)] struct NamedBorrowed<'a> { x: &'a i32, y: &'a i32, } #[derive(Debug)] enum Either<'a> { Num(i32), Ref(&'a 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); }
第七题
/* 让代码工作 */ #[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); } }
第八题
fn fix_me<'a>(foo: &'a Example) -> &'a NoCopyType
第九题
/* 添加合适的生命周期让下面代码工作 */ struct ImportantExcerpt<'a> { part: &'a str, } impl <'a>ImportantExcerpt<'a> { fn level(&'a self) -> i32 { 3 } } fn main() {}
第10题
/* 移除所有可以消除的生命周期标注 */ fn nput(x: &i32) { println!("`annotated_input`: {}", x); } fn pass(x: &i32) -> &i32 { x } fn longest<'a, 'b>(x: &'a str, y: &str) -> &'a str { x } struct Owner(i32); impl Owner { fn add_one(&mut self) { self.0 += 1; } fn print(&self) { println!("`print`: {}", self.0); } } struct Person<'a> { age: u8, name: &'a str, } enum Either<'a> { Num(i32), Ref(&'a i32), } fn main() {}
Beta Was this translation helpful? Give feedback.
All reactions
-
done
Beta Was this translation helpful? Give feedback.
All reactions
-
done
Beta Was this translation helpful? Give feedback.
All reactions
-
done.
Beta Was this translation helpful? Give feedback.