cognitive-engineering-lab / rust-book

The Rust Programming Language: Experimental Edition
https://rust-book.cs.brown.edu
Other
593 stars 92 forks source link

Chapter 4.3 : memory diagram errors #201

Open dhmoclex opened 2 months ago

dhmoclex commented 2 months ago

URL to the section(s) of the book with this problem: https://rust-book.cs.brown.edu/ch04-03-fixing-ownership-errors.html

Description of the problem: Concerning the examples:

fn stringify_name_with_title(name: &Vec<String>) -> String {
    name.push(String::from("Esq."));`{}`
    let full = name.join(" ");
    full
}
fn main() {
    let name = vec![String::from("Ferris")];
    let first = &name[0];
    stringify_name_with_title(&name);
    println!("{}", first);
}

and

fn main() {
let v: Vec<String> = 
  vec![String::from("Hello world")];
let s_ref: &String = &v[0];
let s: String = *s_ref;

// These drops are normally implicit, but we've added them for clarity.
drop(s);
drop(v);
}

The memory diagram shows that the reference to the first string in the vector point to the vector, not the string. According to the following test code, it seems to be false :

fn main() {
    let name = vec![String::from("A"), String::from("B")];
    println!("name: {:p}", &name);
    println!("name_0: {:p}", &name[0]);
    let first = &name[0];
    println!("first: {:p}", first);
    println!("&first: {:p}", &first);
}

Output :

name: 0xc955b6f930 name_0: 0x2b29b410ab0 first: 0x2b29b410ab0 &first: 0xc955b6fa38

Suggested fix: Correct the diagrams so that the reference to the first string in the vector points to the string not the vec.

willcrichton commented 2 months ago

I think you have to be careful in your tests with auto-dereferencing. The &-operator will return a different address depending on the expected type of the &-expression:

fn main() {
    let name = vec![String::from("A"), String::from("B")];
    let a: &Vec<String> = &name;
    let b: &[String] = &name;
    println!("a: {a:p}"); // a: 0x7ffda85297a8
    println!("b: {b:p}"); // b: 0x55a8163c49b0
    println!("name_0: {:p}", &name[0]); // name_0: 0x55a8163c49b0
}
dhmoclex commented 2 months ago

Ok, I'm a bit at a loss here...

use std::mem;

fn main() {
    let name = vec![String::from("A"), String::from("B")];
    let a: &Vec<String> = &name;
    let b: &[String] = &name;
    let c: &String = &name[0];
    let d: &str = &name[0];
    println!("a: {a:p} {}", mem::size_of_val(a));  // a: 0x842330f2a0 24
    println!("b: {b:p} {}", mem::size_of_val(b));  // b: 0x22ca8fbfed0 48
    println!("c: {c:p} {}", mem::size_of_val(c));  // c: 0x22ca8fbfed0 24
    println!("d: {d:p} {}", mem::size_of_val(d));  // d: 0x22ca8fbaf70 1
}
dhmoclex commented 2 months ago

Hi again,

I've done another test :

use std::mem;

fn main() {
    let name = vec![String::from("A"), String::from("B")];
    let a: &Vec<String> = &name;
    let b: &[String] = &name;
    let c: &String = &name[0];
    let d: &String = &name[1];
    let e: &str = &name[0];
    let f: &str = &name[1];
    println!("a: {a:p} {}", mem::size_of_val(a)); // a: 0xe37d4ff5c8 24
    println!("b: {b:p} {}", mem::size_of_val(b)); // b: 0x276383303b0 48
    println!("c: {c:p} {}", mem::size_of_val(c)); // c: 0x276383303b0 24
    println!("d: {d:p} {}", mem::size_of_val(d)); // d: 0x276383303c8 24
    println!("e: {e:p} {}", mem::size_of_val(e)); // e: 0x2763832af70 1
    println!("f: {f:p} {}", mem::size_of_val(f)); // f: 0x2763832af90 1
}

It seems that &name[1] do not point to name but the actual String "B", that would says that the diagrams are indeed erroneous, no ? (Not by much, but still...)