Skip to content

Instantly share code, notes, and snippets.

@xpepper
Last active April 20, 2024 14:27
Show Gist options
  • Save xpepper/d4e8bbe9fd399d68365357192f1fa8d4 to your computer and use it in GitHub Desktop.
Save xpepper/d4e8bbe9fd399d68365357192f1fa8d4 to your computer and use it in GitHub Desktop.
practicing ownership and borrowing (chatGPT 4 Turbo via perplexity.ai)

Certainly! I'll provide you with some code examples that illustrate common mistakes related to ownership and borrowing in Rust. For each example, you can determine whether it would compile or not, and I'll explain why it should or should not compile based on Rust's rules.

Example 1: Multiple Ownership Attempt

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
    let s3 = s1;

    println!("s1: {}, s2: {}, s3: {}", s1, s2, s3);
}

Would this compile? Why or why not?

Example 2: Mutable and Immutable References

fn main() {
    let mut s = String::from("hello");

    let r1 = &s; // Immutable reference
    let r2 = &mut s; // Mutable reference

    println!("r1: {}, r2: {}", r1, r2);
}

Would this compile? Why or why not?

Example 3: Dangling Reference

fn main() {
    let r = dangle();

    println!("Dangling reference: {}", r);
}

fn dangle() -> &String {
    let s = String::from("hello");
    &s
}

Would this compile? Why or why not?

Example 4: Borrowing After Ownership Transfer

fn main() {
    let s1 = String::from("hello");
    let s2 = takes_and_gives_back(s1);

    println!("s1: {}", s1);
    println!("s2: {}", s2);
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string
}

Would this compile? Why or why not?

Example 5: Simultaneous Mutable References

fn main() {
    let mut s = String::from("hello");

    {
        let r1 = &mut s;
    }

    let r2 = &mut s;
    let r3 = &mut s;

    println!("r2: {}, r3: {}", r2, r3);
}

Would this compile? Why or why not?


For each example, consider the following Rust rules:

  • Ownership can only be held by one variable at a time. When ownership is transferred, the previous owner can no longer be used[1].
  • You cannot have a mutable reference while an immutable reference exists[2].
  • References must always be valid. Returning a reference to a local variable that goes out of scope creates a dangling reference, which is invalid[2].
  • Once a variable's ownership has been transferred, it cannot be used again unless ownership is explicitly returned[1].
  • You can have multiple mutable references, but not simultaneously. Only one mutable reference can be active at a time in a particular scope[2].

Citations:

@xpepper
Copy link
Author

xpepper commented Apr 19, 2024

Produced with chatGTP 4 Turbo and the following prompt:

I'm trying to learn ownership (https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) and borrowing (https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html) in Rust programming language, and I would like you to help me practicing in recognizing code that violates Rust rules on ownership and borrowing, by showing me some code examples and then let me choose, for each example, if it would compile or not (and why it should not compile).

I'm going to give you same examples, please use them to have an idea of what kind of code example you could show me, but don't just copy those examples, try to come out with your own examples.

For example you could show me a code example like this

1 let s1 = String::from("hello");
2 let s2 = s1;
3 
4 println!("{}, world!", s1);

And I would have to recognize that this code does not compile because at line 4 s1 would be an invalid reference, since ownership moved to s2.

Another example you could show me would be something like this

fn main() {
    let s = String::from("hello");  

    takes_ownership(s);             
                                    
    let x = 5;                      

    makes_copy(x);                  

} 
  

fn takes_ownership(some_string: String) { 
    println!("{}", some_string);
} 
  

fn makes_copy(some_integer: i32) { 
    println!("{}", some_integer);
} 

Or this, for help me understand borrowing

fn main() {
    let s = String::from("hello");

    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}

Or this one

let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment