In this lesson we'll learn how to read user input from stdin, using Rust's std::io
module and its Stdin
object.
I know I'm getting caught up in the technical details here, but I'm curious a) why the ampersand precedes the mut
keyword, as opposed to mut &name
, and b) why the keyword is necessary at all when passing the argument to read_line
. We've already defined name
as mutable, so shouldn't a reference to it be sufficient? But when I try read_line(&name)
, the compiler tells me:
note: expected mutable reference `&mut std::string::String`
found reference `&std::string::String`
So I get the feeling I'm not quite grasping how exactly mut
is working.
Hi Matt,
why the ampersand precedes the mut keyword, as opposed to mut &name As mentioned in your other comments, I'm no compiler expert, so this is just a guess:
The ampersand expresses a reference to something so &name
is a reference to the data name
in memory. Pretty much everything in rust is an expression like 1+1
, some_variable + 1
etc. I believe that, having an expression like mut &name
conveys very different semantics from what's the intention here. mut
won't have a meaning but could maybe be a variable name and &name
is, already, clearly an immutable reference to name
.
I could imagine that going with &mut name
makes the expression less ambiguous. But again, just a guess. Great question!
why the keyword is necessary at all when passing the argument to read_line. We've already defined name as mutable, so shouldn't a reference to it be sufficient?
As the compiler errors says, passing a &reference
to an API that expects a &mut Type
cannot work. This is because also reference are by default immutable.
let mut name = "Pascal"; // `name` is mutable
let r = &name; // `r` is immutable`
Now in the case of the code in this lesson it might not be as obvious because we're not creating a variable for the &mut name
but instead pass it straight to the API. You could write it like this:
let mut name = String::new();
let r = &mut name;
io::stdin().read_line(r).unwrap();
Does that make sense?
Does that make sense?
Thanks, after reading a bunch of articles and thinking about it more, I think I understand this now. We start by declaring name
as mutable so that it can be changed by the later code. However, we immediately then pass a reference to name
in the next line. As you said, references are immutable by default, and this one is pointing to the state of name
at the time the reference was created, when it is an empty string. So that means that the reference is a pointer to an empty buffer on the heap. When the input modifies the string, it could (and in this case certainly would) create a new buffer on the heap to fit the new contents, which means the reference pointing to the old buffer is no longer valid, or at least useful. Therefore the reference itself must mutate, to point to the new buffer, in order for the original variable name
to own the new buffer (i.e. the correct data). Yes? Or something like that; I'm still absorbing a lot of new information.
When the input modifies the string, it could (and in this case certainly would) create a new buffer on the heap to fit the new contents, which means the reference pointing to the old buffer is no longer valid, or at least useful. Therefore the reference itself must mutate, to point to the new buffer, in order for the original variable name to own the new buffer (i.e. the correct data). Yes? Or something like that; I'm still absorbing a lot of new information.
That pretty much nailed it.