Conceptos erróneos comunes sobre la vida en Rust

(nota del traductor: la vida es una de las cosas más confusas en Rust, lo que a menudo causa dificultades para los principiantes, incluso a pesar de la documentación oficial . Hay explicaciones sobre ciertos aspectos de la vida, pero todas están dispersas en diferentes fuentes y respuestas. en Stack Overflow. El autor de este artículo ha recopilado en un solo lugar y ha aclarado muchos temas relacionados con la vida, lo que hace que este artículo sea tan valioso (y yo mismo aprendí cosas nuevas aquí). Decidí traducirlo para que pueda ser leído por aquellos que no habla inglés lo suficiente como para leer el original con fluidez y también para aumentar la popularidad de este artículo entre la comunidad de Rust de habla rusa)



19 de mayo de 2020 37 minutos #rust # vidas



Tabla de contenido





Introducción



- , , . , .



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 T T: '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 TT, , . , 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: 'staticT, , . 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 T
  • T: '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 T
  • T: 'static , « T 'static»
  • T: 'static, T 'static .
  • T: 'static , , T

    • -
  • T: 'a , &'a T
  • T: '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


















Rust, nlinker.




All Articles