Why this code has an error?

fn main() {
    let mut cadena = String::from("Hola");
    cadena.push_str(" Mundo!");
    
    println!("{cadena}");
    
    let mut cadena2 = cadena.clone();
    
    println!("No hay Error {cadena}");
    
    toma_cadena(&mut cadena2);
    
    println!("No hay Error {cadena}");
    println!("Hay Error {cadena2}");
    
    let _cadena3 = &mut cadena2;
    {
        let _cadena4 = &mut cadena2;
        //println!("{}", cadena4);
    }
    
    println!("{}", cadena3);
}

fn toma_cadena(un_string: &mut String) {
    println!("Imprimir cadena desde la funcion: {un_string}");
    un_string.push_str(" oh oh")
}

(Playground)

Output:

Hola Mundo!
No hay Error Hola Mundo!
Imprimir cadena desde la funcion: Hola Mundo!
No hay Error Hola Mundo!
Hay Error Hola Mundo! oh oh

Errors:

   Compiling playground v0.0.1 (/playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/playground`

If you are referring to the section labeled "Standard Error" in the Rust Playground, that doesn't mean the program has an error. Instead, it refers to terminology of how programs interact with the terminal (or with each other) on Unix-like operating systems.

You can read more about this online, e. g. on Wikipedia

The first paragraph to stderr, the "Standard Error" stream, explains

Standard error is another output stream typically used by programs to output error messages or diagnostics. It is a stream independent of standard output and can be redirected separately.

And that's all there is to this. The Rust Playground shows the output of the Rust compiler, e. g. via cargo run executed on a terminal. The command cargo run compiles the code and executes it. It outputs both some diagnostics from the compiler informing about what it's doing while translating your program into machine code, and then also executes the program and shows it's output. In order to make it easier to get a clean program output out of this, the compiler's diagnostics are communicated via stderr, not stdout. It's using it because that's an appropriate choice for diagnostics, and it can allow users to separate out those diagnostics from the more important data your actual program writes to stdout when executed.


Or maybe I'm misunderstand your question entirely and this is about the Spanish text printed by the program behavior. Like that it prints something about an error? Or the string being modified? Or are you asking about the compilation errors of some of the commented-out lines are included?

(Hint: for a higher chance of getting helpful answers, formulate a more clear question :wink:)

If I uncomment all the commented lines in your playground I get the following compiler error. Is this the error you're referring to?

error[E0499]: cannot borrow `cadena2` as mutable more than once at a time
  --> src/main.rs:18:23
   |
16 |     let cadena3 = &mut cadena2;
   |                   ------------ first mutable borrow occurs here
17 |     {
18 |         let cadena4 = &mut cadena2;
   |                       ^^^^^^^^^^^^ second mutable borrow occurs here
...
22 |     println!("{}", cadena3);
   |                    ------- first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` (bin "playground") due to 1 previous error
1 Like

The inner block { .. } doesn't change the borrow checker analysis in this case...

    let cadena3 = &mut cadena2;
    {
        let cadena4 = &mut cadena2;
        println!("{}", cadena4);
    }
    
    println!("{}", cadena3);

...so this code does the same thing:

    let cadena3 = &mut cadena2;

    let cadena4 = &mut cadena2;
    println!("{}", cadena4);

    println!("{}", cadena3);

And the problem is that cadena2 is exclusive borrowed from the top line until the bottom line, where cadena3 is used. It's an error to try to use cadena2 directly while it's exclusively borrowed.

    let cadena3 = &mut cadena2; // -- start borrow ----+
    //                                                 |
    let cadena4 = &mut cadena2; // --------------------X--- error
    println!("{}", cadena4); //                        |
    //                                                 |
    println!("{}", cadena3); // last use of cadena3    |
    // ------------------------------ end borrow ------+
4 Likes

yeah the thing that i dont understand is that if i borrowed the memory from cadena2 into cadena 3 then make block of code and borrowed the same memori from cadena2 into cadena4 but this block of code stops to exits afert its finished so it means the reference to cadena2 now is only borrowed from cadena3 but if try to printit the compiler says that i had more than once mutable reference to the same memory

Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow cadena2 as mutable more than once at a time
--> src/main.rs:18:24
|
16 | let cadena3 = &mut cadena2;
| ------------ first mutable borrow occurs here
17 | {
18 | let _cadena4 = &mut cadena2;
| ^^^^^^^^^^^^ second mutable borrow occurs here
...
22 | println!("{}", cadena3);
| ------- first borrow later used here

For more information about this error, try rustc --explain E0499.
error: could not compile playground (bin "playground") due to 1 previous error

/// real code that had my questions

fn main() {
let mut cadena = String::from("Hola");
cadena.push_str(" Mundo!");

println!("{cadena}");

let mut cadena2 = cadena.clone();

println!("No hay Error {cadena}");

toma_cadena(&mut cadena2);

println!("No hay Error {cadena}");
println!("Hay Error {cadena2}");

let cadena3 = &mut cadena2;
{
    let _cadena4 = &mut cadena2;
    //println!("{}", cadena4);
}

println!("{}", cadena3);

}

fn toma_cadena(un_string: &mut String) {
println!("Imprimir cadena desde la funcion: {un_string}");
un_string.push_str(" oh oh")
}

The borrow checker does not reason like so:

  • cadena3 and cadena4 are both pointing at cadena2
  • cadena4 was created later than cadena3 and then went out of scope
  • so now it's ok to use cadena3 again

Instead it is more like so:

  • cadena2 is exclusively borrowed for some lifetime 'x
  • cadena2 can't be directly used so long as it is exclusively borrowed
  • 'x has to be alive everywhere cadena3 is used

For an example of why the presence of the block doesn't mean the borrow you stored in cadena4 has to be dead, consider this playground.

    let reborrower;
    let cadena3 = &mut cadena2;
    {
        let cadena4 = &mut cadena2;
        reborrower = &mut *cadena4;
    }

    println!("{reborrower}");

The lifetimes (borrows) in the type of a reference variable aren't limited by the block they are in. That's why you can store a &'static str in a local variable, say. And you can reborrow that data and then let the reference go out of scope, too, without killing the borrow (like in the example above).

This functionality has to exist in some form, because that's what allows returning borrows from a function.

fn first(vec: &mut Vec<String>) -> &mut String {
    let elem_0 = &mut vec[0];
    elem_0
}
// `vec` goes out of scope at the end of `first`,
// but you can still use the returned `&mut String`
// that `first` returns to you

To the borrow checker, a reference going out of scope only matters if you borrowed the reference itself, not what's behind the reference. Like if you take a reference to a reference. So this one does fail:

    let borrow_of_borrow;
    let cadena3 = &mut cadena2;
    {
        let cadena4 = &mut cadena2;
        borrow_of_borrow = &cadena4;
    }

    println!("{borrow_of_borrow}");

You're not doing that in your examples, so the inner block doesn't change anything from a borrow checking perspective.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.