(ملاحظة المترجم: العمر هو أحد الأشياء الأكثر إرباكًا في Rust ، والتي غالبًا ما تسبب صعوبة للمبتدئين ، على الرغم من الوثائق الرسمية . هناك تفسيرات حول الجوانب الفردية من العمر ، لكنها كلها مبعثرة عبر مصادر وإجابات مختلفة على Stack Overflow. جمع مؤلف هذه المقالة في مكان واحد الكثير من القضايا المتعلقة بالحياة ، مما يجعل هذه المقالة ذات قيمة كبيرة (تعلمت أشياء جديدة من هنا بنفسي). قررت ترجمتها بحيث يمكن قراءتها من قبل أولئك الذين لا يتحدث الإنجليزية بشكل كافٍ لقراءة النص الأصلي بطلاقة ، وكذلك لرفع مستوى هذه المقالة بين مجتمع Rust الناطق باللغة الروسية)
19 مايو ، 2020 37 minutes #rust # lifetimes
جدول المحتويات
- المقدمة
- أوهام
1) Tيحتوي على أنواع خاصة فقط2) T: 'static، ثمTيجب أن يستمر طوال مدة البرنامج3) &'a TوT: 'a- أنها هي نفسها- 4) الكود الخاص بي ليس عامًا وليس له عمر
- 5) إذا تم تجميعها ، فستكون التعليقات التوضيحية طوال حياتي صحيحة
- 6) كائنات السمات الموجودة خلف مؤشرات امتلاكها ليس لها عمر
- 7) رسائل خطأ في الترجمة ستخبرني بكيفية إصلاح برنامجي
- 8) العمر يمكن أن ترتفع وتنخفض في وقت التشغيل
- 9) إضعاف روابط mut إلى الروابط المشتركة بأمان
- 10) تتبع عمليات الإغلاق نفس القواعد للاستدلال الضمني على استبعاد مدى الحياة كوظائف
11) 'staticالروابط يمكن أن تؤدي دائمًا إلى'a
- خاتمة
- نقاش
- جهات الاتصال
- قراءة متعمقة
المقدمة
- , , . , .
T |
1)
2) |
, , , i32, String, Vec . . |
|
| 1)
2) |
, , &i32, &mut i32 . . |
| 1) mut-
2) |
, .. &mut T |
| 1) immut-
2) |
, .. &T |
: — , , , . ~6500 , .
1) T
, , Rust, , . :
Rust, , i32, &i32 &mut i32 — . , T , . , , , . , Rust :
T |
&T |
&mut T |
|
i32 |
&i32 |
&mut i32 |
T . &T . &mut T . T, &T &mut T — . , , , , . Rust -:
T |
&T |
&mut T |
|
i32, &i32, &mut i32, &&i32, &mut &mut i32, ... |
&i32, &&i32, &&mut i32, ... |
&mut i32, &mut &mut i32, &mut &i32, ... |
T, &T &mut T — , . T &T &mut T, &T &mut T — . , :
trait Trait {}
impl<T> Trait for T {}
impl<T> Trait for &T {} //
impl<T> Trait for &mut T {} //
, :
error[E0119]: conflicting implementations of trait `Trait` for type `&_`:
--> src/lib.rs:5:1
|
3 | impl<T> Trait for T {}
| ------------------- first implementation here
4 |
5 | impl<T> Trait for &T {}
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
error[E0119]: conflicting implementations of trait `Trait` for type `&mut _`:
--> src/lib.rs:7:1
|
3 | impl<T> Trait for T {}
| ------------------- first implementation here
...
7 | impl<T> Trait for &mut T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut _`
Trait &T &mut T, Trait T, &T &mut T. , , &T &mut T :
trait Trait {}
impl<T> Trait for &T {} //
impl<T> Trait for &mut T {} //
T&T,&mut T&T&mut T
2) T: 'static, T
T: 'static«T'static»&'static TT: 'static—-
T: 'static,T -
T: 'static,T
Rust 'static, , :
fn main() {
let str_literal: &'static str = "str literal";
}
, "str literal" , , 'static. static static .
static BYTES: [u8; 3] = [1, 2, 3];
static mut MUT_BYTES: [u8; 3] = [1, 2, 3];
fn main() {
MUT_BYTES[0] = 99; // ,
unsafe {
MUT_BYTES[0] = 99;
assert_eq!(99, MUT_BYTES[0]);
}
}
static :
- ,
'static , , - static , ? , 'static , ?
, , , 'static, , 'static. , , .
&'static T T: 'static.
&'static T — T, , . , T . T . 'static , :
use rand;
// 'static str
fn rand_str_generator() -> &'static str {
let rand_string = rand::random::<u64>().to_string();
Box::leak(rand_string.into_boxed_str())
}
T: 'static — T, , . T: 'static &'static T, , String, Vec . . , , , , , . T: 'static , «T 'static», «T 'static». :
use rand;
fn drop_static<T: 'static>(t: T) {
std::mem::drop(t);
}
fn main() {
let mut strings: Vec<String> = Vec::new();
for _ in 0..10 {
if rand::random() {
//
//
let string = rand::random::<u64>().to_string();
strings.push(string);
}
}
// ,
// 'static
for mut string in strings {
//
string.push_str("a mutation");
//
drop_static(string); //
}
//
println!("i am the end of the program");
}
T: 'static, «T'static»-
T: 'static,T'static. -
T: 'static, ,T
3) &'a T T: 'a —
.
&'a T T: 'a, T, 'a, 'a, T 'a. , Rust &'static Ref<'a, T> Ref 'a, 'static .
T: 'a &'a T, .
// , 'a
fn t_ref<'a, T: 'a>(t: &'a T) {}
// , 'a
fn t_bound<'a, T: 'a>(t: T) {}
// ,
struct Ref<'a, T: 'a>(&'a T);
fn main() {
let string = String::from("string");
t_bound(&string); //
t_bound(Ref(&string)); //
t_bound(&Ref(&string)); //
t_ref(&string); //
t_ref(Ref(&string)); // , ,
t_ref(&Ref(&string)); //
// 'static, , , 'a
t_bound(string); //
}
T: 'a,&'a TT: 'a, , ,&'a T-
T: 'static,T: 'a,'static>='a'a
4)
- (lifetime elision), , Rust :
- -
- , (. : , , )
- , —
&self&mut self,self
, :
//
fn print(s: &str);
//
fn print<'a>(s: &'a str);
//
fn trim(s: &str) -> &str;
//
fn trim<'a>(s: &'a str) -> &'a str;
// , ,
// . .
fn get_str() -> &str;
//
fn get_str<'a>() -> &'a str; //
fn get_str() -> &'static str; // 'static
// , ,
// . .
fn overlap(s: &str, t: &str) -> &str;
//
// ( )
fn overlap<'a>(s: &'a str, t: &str) -> &'a str; // s
fn overlap<'a>(s: &str, t: &'a str) -> &'a str; // t
fn overlap<'a>(s: &'a str, t: &'a str) -> &'a str; // s t
fn overlap(s: &str, t: &str) -> &'static str; // s t
fn overlap<'a>(s: &str, t: &str) -> &'a str; //
//
fn overlap<'a, 'b>(s: &'a str, t: &'b str) -> &'a str;
fn overlap<'a, 'b>(s: &'a str, t: &'b str) -> &'b str;
fn overlap<'a>(s: &'a str, t: &'a str) -> &'a str;
fn overlap<'a, 'b>(s: &'a str, t: &'b str) -> &'static str;
fn overlap<'a, 'b, 'c>(s: &'a str, t: &'b str) -> &'c str;
//
fn compare(&self, s: &str) -> &str;
//
fn compare<'a, 'b>(&'a self, &'b str) -> &'a str;
- :
- ,
- ,
- - ( )
- ( )
.
- Rust ,
5) ,
- (borrow checker) Rust , ,
- Rust
Rust , . :
struct ByteIter<'a> {
remainder: &'a [u8]
}
impl<'a> ByteIter<'a> {
fn next(&mut self) -> Option<&u8> {
if self.remainder.is_empty() {
None
} else {
let byte = &self.remainder[0];
self.remainder = &self.remainder[1..];
Some(byte)
}
}
}
fn main() {
let mut bytes = ByteIter { remainder: b"1" };
assert_eq!(Some(&b'1'), bytes.next());
assert_eq!(None, bytes.next());
}
ByteIter — , . Iterator. , , , ?
fn main() {
let mut bytes = ByteIter { remainder: b"1123" };
let byte_1 = bytes.next();
let byte_2 = bytes.next();
if byte_1 == byte_2 {
// -
}
}
! :
error[E0499]: cannot borrow `bytes` as mutable more than once at a time
--> src/main.rs:20:18
|
19 | let byte_1 = bytes.next();
| ----- first mutable borrow occurs here
20 | let byte_2 = bytes.next();
| ^^^^^ second mutable borrow occurs here
21 | if byte_1 == byte_2 {
| ------ first borrow later used here
, . — , , ByteIter , &'a [T], , /. , , , , , , ?
, ! , . , :
struct ByteIter<'a> {
remainder: &'a [u8]
}
impl<'a> ByteIter<'a> {
fn next<'b>(&'b mut self) -> Option<&'b u8> {
if self.remainder.is_empty() {
None
} else {
let byte = &self.remainder[0];
self.remainder = &self.remainder[1..];
Some(byte)
}
}
}
. . , Rust: . :
struct ByteIter<'remainder> {
remainder: &'remainder [u8]
}
impl<'remainder> ByteIter<'remainder> {
fn next<'mut_self>(&'mut_self mut self) -> Option<&'mut_self u8> {
if self.remainder.is_empty() {
None
} else {
let byte = &self.remainder[0];
self.remainder = &self.remainder[1..];
Some(byte)
}
}
}
'mut_self, 'remainder! .
struct ByteIter<'remainder> {
remainder: &'remainder [u8]
}
impl<'remainder> ByteIter<'remainder> {
fn next(&mut self) -> Option<&'remainder u8> {
if self.remainder.is_empty() {
None
} else {
let byte = &self.remainder[0];
self.remainder = &self.remainder[1..];
Some(byte)
}
}
}
fn main() {
let mut bytes = ByteIter { remainder: b"1123" };
let byte_1 = bytes.next();
let byte_2 = bytes.next();
std::mem::drop(bytes); // !
if byte_1 == byte_2 { //
// -
}
}
, , , . Rust ? : (memory safe).
(borrow checker) Rust- , . Rust , - .
, : Rust , .
#[derive(Debug)]
struct NumRef<'a>(&'a i32);
impl<'a> NumRef<'a> {
// 'a,
// self 'a, ? (: , )
fn some_method(&'a mut self) {}
}
fn main() {
let mut num_ref = NumRef(&5);
num_ref.some_method(); // num_ref
num_ref.some_method(); //
println!("{:?}", num_ref); //
}
- , 'a, &'a mut self. Rust, « ». , Rust some_method, , , . , , , , . , Rust:
#[derive(Debug)]
struct NumRef<'a>(&'a i32);
impl<'a> NumRef<'a> {
// mut self 'a
fn some_method(&mut self) {}
//
fn some_method_desugared<'b>(&'b mut self){}
}
fn main() {
let mut num_ref = NumRef(&5);
num_ref.some_method();
num_ref.some_method(); //
println!("{:?}", num_ref); //
}
- Rust
- Rust ,
- ,
6) -
Rust . Rust -:
- - ́ , -
- , ,
- , , ,
- ,
- ,
-
'static,'static - , ,
'static
, « - ». , , , :
use std::cell::Ref;
trait Trait {}
//
type T1 = Box<dyn Trait>;
// , Box<T> T,
// 'static
type T2 = Box<dyn Trait + 'static>;
//
impl dyn Trait {}
//
impl dyn Trait + 'static {}
//
type T3<'a> = &'a dyn Trait;
// , &'a T T: 'a, 'a
type T4<'a> = &'a (dyn Trait + 'a);
//
type T5<'a> = Ref<'a, dyn Trait>;
// , Ref<'a, T> T: 'a, 'a
type T6<'a> = Ref<'a, dyn Trait + 'a>;
trait GenericTrait<'a>: 'a {}
//
type T7<'a> = Box<dyn GenericTrait<'a>>;
//
type T8<'a> = Box<dyn GenericTrait<'a> + 'a>;
//
impl<'a> dyn GenericTrait<'a> {}
//
impl<'a> dyn GenericTrait<'a> + 'a {}
, , , , , , - . , , , :
trait Trait {}
struct Struct {}
struct Ref<'a, T>(&'a T);
impl Trait for Struct {}
impl Trait for &Struct {} //
impl<'a, T> Trait for Ref<'a, T> {} // ,
, , , - . :
use std::fmt::Display;
fn dynamic_thread_print(t: Box<dyn Display + Send>) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
fn static_thread_print<T: Display + Send>(t: T) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
:
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:10:5
|
9 | fn static_thread_print<T: Display + Send>(t: T) {
| -- help: consider adding an explicit lifetime bound...: `T: 'static +`
10 | std::thread::spawn(move || {
| ^^^^^^^^^^^^^^^^^^
|
note: ...so that the type `[closure@src/lib.rs:10:24: 12:6 t:T]` will meet its required lifetime bounds
--> src/lib.rs:10:5
|
10 | std::thread::spawn(move || {
| ^^^^^^^^^^^^^^^^^^
, , . .
use std::fmt::Display;
fn dynamic_thread_print(t: Box<dyn Display + Send>) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
fn static_thread_print<T: Display + Send + 'static>(t: T) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
, . 'static T, — ? . , Rust 'static , 'static. Rust:
use std::fmt::Display;
fn dynamic_thread_print(t: Box<dyn Display + Send + 'static>) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
fn static_thread_print<T: Display + Send + 'static>(t: T) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
- -
7) ,
- -
- Rust
— , :
use std::fmt::Display;
fn box_displayable<T: Display>(t: T) -> Box<dyn Display> {
Box::new(t)
}
:
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:4:5
|
3 | fn box_displayable<T: Display>(t: T) -> Box<dyn Display> {
| -- help: consider adding an explicit lifetime bound...: `T: 'static +`
4 | Box::new(t)
| ^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/lib.rs:4:5
|
4 | Box::new(t)
| ^^^^^^^^^^^
, , . , , , - 'static :
use std::fmt::Display;
fn box_displayable<T: Display + 'static>(t: T) -> Box<dyn Display> {
Box::new(t)
}
, … , ? , , , . , :
use std::fmt::Display;
fn box_displayable<'a, T: Display + 'a>(t: T) -> Box<dyn Display + 'a> {
Box::new(t)
}
, , ! ? , . , :
fn return_first(a: &str, b: &str) -> &str {
a
}
:
error[E0106]: missing lifetime specifier
--> src/lib.rs:1:38
|
1 | fn return_first(a: &str, b: &str) -> &str {
| ---- ---- ^ 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
|
1 | fn return_first<'a>(a: &'a str, b: &'a str) -> &'a str {
| ^^^^ ^^^^^^^ ^^^^^^^ ^^^
. , , . :
fn return_first<'a>(a: &'a str, b: &str) -> &'a str {
a
}
- -
- Rust ,
- Rust , , , , .
8)
- ,
- Rust
:
struct Has<'lifetime> {
lifetime: &'lifetime str,
}
fn main() {
let long = String::from("long");
let mut has = Has { lifetime: &long };
assert_eq!(has.lifetime, "long");
{
let short = String::from("short");
// ""
has.lifetime = &short;
assert_eq!(has.lifetime, "short");
// " " ( )
has.lifetime = &long;
assert_eq!(has.lifetime, "long");
// `short`
}
// , `short` ""
assert_eq!(has.lifetime, "long");
}
:
error[E0597]: `short` does not live long enough
--> src/main.rs:11:24
|
11 | has.lifetime = &short;
| ^^^^^^ borrowed value does not live long enough
...
15 | }
| - `short` dropped here while still borrowed
16 | assert_eq!(has.lifetime, "long");
| --------------------------------- borrow later used here
, :
struct Has<'lifetime> {
lifetime: &'lifetime str,
}
fn main() {
let long = String::from("long");
let mut has = Has { lifetime: &long };
assert_eq!(has.lifetime, "long");
//
if false {
let short = String::from("short");
// ""
has.lifetime = &short;
assert_eq!(has.lifetime, "short");
// " " ( )
has.lifetime = &long;
assert_eq!(has.lifetime, "long");
// `short`
}
// , `short` ""
assert_eq!(has.lifetime, "long");
}
, , , if-else match , . , . , .
- , -
- Rust , ,
9) mut-
- (re-borrowing)
mut- , , Rust mut- :
fn takes_shared_ref(n: &i32) {}
fn main() {
let mut a = 10;
takes_shared_ref(&mut a); //
takes_shared_ref(&*(&mut a)); //
}
, mut- , ? — , :
fn main() {
let mut a = 10;
let b: &i32 = &*(&mut a); //
let c: &i32 = &a;
dbg!(b, c); //
}
:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:4:19
|
3 | let b: &i32 = &*(&mut a);
| -------- mutable borrow occurs here
4 | let c: &i32 = &a;
| ^^ immutable borrow occurs here
5 | dbg!(b, c);
| - mutable borrow later used here
, , . Rust , mut-? , mut- :
use std::sync::Mutex;
struct Struct {
mutex: Mutex<String>
}
impl Struct {
// self
fn get_string(&mut self) -> &str {
self.mutex.get_mut().unwrap()
}
fn mutate_string(&self) {
// Rust ,
//
// , get_string
*self.mutex.lock().unwrap() = "surprise!".to_owned();
}
}
fn main() {
let mut s = Struct {
mutex: Mutex::new("string".to_owned())
};
let str_ref = s.get_string(); //
s.mutate_string(); // str_ref ,
dbg!(str_ref); // ,
}
, mut- , , : , . , , . , , , . , Rust -. - , , :
// T T
fn some_function<T>(some_arg: &mut T) -> &T;
struct Struct;
impl Struct {
// self
fn some_method(&mut self) -> &Self;
// self T
fn other_method(&mut self) -> &T;
}
, Rust - , , :
use std::collections::HashMap;
type PlayerID = i32;
#[derive(Debug, Default)]
struct Player {
score: i32,
}
fn start_game(player_a: PlayerID, player_b: PlayerID, server: &mut HashMap<PlayerID, Player>) {
// ,
let player_a: &Player = server.entry(player_a).or_default();
let player_b: &Player = server.entry(player_b).or_default();
// -
dbg!(player_a, player_b); //
}
. or_default() &mut Player, &Player - . , , :
use std::collections::HashMap;
type PlayerID = i32;
#[derive(Debug, Default)]
struct Player {
score: i32,
}
fn start_game(player_a: PlayerID, player_b: PlayerID, server: &mut HashMap<PlayerID, Player>) {
// Player,
server.entry(player_a).or_default();
server.entry(player_b).or_default();
// , ,
let player_a = server.get(&player_a);
let player_b = server.get(&player_b);
// -
dbg!(player_a, player_b); //
}
, , — , .
(. : . , server : Player, . Player , . , , , . Rust , Player )
- mut- ,
- mut- ,
10) ,
, .
, , , , .
fn function(x: &i32) -> &i32 {
x
}
fn main() {
let closure = |x: &i32| x;
}
:
error: lifetime may not live long enough
--> src/main.rs:6:29
|
6 | let closure = |x: &i32| x;
| - - ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i32
| let's call the lifetime of this reference `'1`
:
//
fn function<'a>(x: &'a i32) -> &'a i32 {
x
}
fn main() {
//
let closure = for<'a, 'b> |x: &'a i32| -> &'b i32 { x };
// , Rust,
}
. , , , , . ? :
fn main() {
// -, , ,
let identity: dyn Fn(&i32) -> &i32 = |x: &i32| x;
// , -
let identity: Box<dyn Fn(&i32) -> &i32> = Box::new(|x: &i32| x);
// ,
let identity: &dyn Fn(&i32) -> &i32 = &|x: &i32| x;
// :)
let identity: &'static (dyn for<'a> Fn(&'a i32) -> &'a i32 + 'static) = &|x: &i32| -> &i32 { x };
// ,
let identity: impl Fn(&i32) -> &i32 = |x: &i32| x;
// ,
let identity = for<'a> |x: &'a i32| -> &'a i32 { x };
// "impl trait"
fn return_identity() -> impl Fn(&i32) -> &i32 {
|x| x
}
let identity = return_identity();
//
fn annotate<T, F>(f: F) -> F where F: Fn(&T) -> &T {
f
}
let identity = annotate(|x: &i32| x);
}
, , , .
- , .
11) 'static- 'a-
:
fn get_str<'a>() -> &'a str; //
fn get_str() -> &'static str; // 'static
, , - . , , , , , .
, , 'static- , 'a-, Rust 'static- 'a- . : , , . , , .
use rand;
fn generic_str_fn<'a>() -> &'a str {
"str"
}
fn static_str_fn() -> &'static str {
"str"
}
fn a_or_b<T>(a: T, b: T) -> T {
if rand::random() {
a
} else {
b
}
}
fn main() {
let some_string = "string".to_owned();
let some_str = &some_string[..];
let str_ref = a_or_b(some_str, generic_str_fn()); //
let str_ref = a_or_b(some_str, static_str_fn()); //
}
, , :
use rand;
fn generic_str_fn<'a>() -> &'a str {
"str"
}
fn static_str_fn() -> &'static str {
"str"
}
fn a_or_b_fn<T, F>(a: T, b_fn: F) -> T
where F: Fn() -> T
{
if rand::random() {
a
} else {
b_fn()
}
}
fn main() {
let some_string = "string".to_owned();
let some_str = &some_string[..];
let str_ref = a_or_b_fn(some_str, generic_str_fn); //
let str_ref = a_or_b_fn(some_str, static_str_fn); //
}
:
error[E0597]: `some_string` does not live long enough
--> src/main.rs:23:21
|
23 | let some_str = &some_string[..];
| ^^^^^^^^^^^ borrowed value does not live long enough
...
25 | let str_ref = a_or_b_fn(some_str, static_str_fn);
| ---------------------------------- argument requires that `some_string` is borrowed for `'static`
26 | }
| - `some_string` dropped here while still borrowed
— , &'static str &'a str, for<T> Fn() -> &'static T for<'a, T> Fn() -> &'a T. — , — .
-
for<'a, T> fn() -> &'a T,for<T> fn() -> &'static T
T&T,&mut T&T&mut TT: 'static, «T'static»-
T: 'static,T'static. -
T: 'static, ,T
- -
T: 'a,&'a TT: 'a, , ,&'a T-
T: 'static,T: 'a,'static>='a'a - Rust ,
- Rust
- Rust ,
- ,
- -
- Rust , , , , .
- , -
- Rust , ,
- ,
- mut- ,
-
for<'a, T> fn() -> &'a T,for<T> fn() -> &'static T
- pretzelhammer Twitter
- (
WatchReleases only)
Rust, nlinker.