I am confused with borrowing and ownership. In the Rust documentation about reference and borrowing
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
They say
println! can borrow x.
I am confused by this. If println! borrows x, why does it pass x not &x?
I try to run this code below
fn main() {
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", &x);
}
This code is identical with the code above except I pass &x to println!. It prints '6' to the console which is correct and is the same result as the first code.
The macros print!, println!, eprint!, eprintln!, write!, writeln! and format! are a special case and implicitly take a reference to any arguments to be formatted.
These macros do not behave as normal functions and macros do for reasons of convenience; the fact that they take references silently is part of that difference.
fn main() {
let x = 5;
println!("{}", x);
}
Run it through rustc -Z unstable-options --pretty expanded on the nightly compiler and we can see what println! expands to:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
Tidied further, it’s this:
use std::{fmt, io};
fn main() {
let x = 5;
io::_print(fmt::Arguments::new_v1(
&["", "\n"],
&[fmt::ArgumentV1::new(&x, fmt::Display::fmt)],
// ^^
));
}
Note the &x.
If you write println!("{}", &x), you are then dealing with two levels of references; this has the same result because there is an implementation of std::fmt::Display for &T where T implements Display (shown as impl<'a, T> Display for &'a T where T: Display + ?Sized) which just passes it through. You could just as well write &&&&&&&&&&&&&&&&&&&&&&&x.
Early 2023 update:
Since mid-2021, the required invocation has been rustc -Zunpretty=expanded rather than rustc -Zunstable-options --pretty=expanded.
Since 2023-01-28 or so (https://github.com/rust-lang/rust/pull/106745), format_args! is part of the AST, and so the expansion of println!("{}", x) is ::std::io::_print(format_args!("{0}\n", x));, not exposing the Arguments::new_v1 construction and &x aspects. This is good for various reasons (read #106745’s description), but ruins my clear demonstration here that x was only taken by reference. (This is why I’ve added this as a note at the end rather than updating the answer—since it no longer works.)
Related
I'll use the CustomSmartPointer from The Book, which is used to explain the Drop trait, to build an example:
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
println!("A");
let pointer = CustomSmartPointer {
data: String::from("my stuff"),
};
println!("B");
println!("output: {}", pointer.data);
println!("C");
}
This prints:
A
B
output: my stuff
C
Dropping CustomSmartPointer with data `my stuff`!
However, from what I learned I would have expected the last two lines to be swapped. The local variable pointer isn't used anymore after being printed, so I would have expected its scope to end after the line that prints its contents, before "C" gets printed. For example, the section on references has this example:
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// variables r1 and r2 will not be used after this point
let r3 = &mut s; // no problem
println!("{}", r3);
So it seems like either (1) the Drop trait extends the scope until the end of the current block, or (2) it is only references whose scope ends "ASAP" and everything else already lives until the end of the current block (and that would be a major difference between references and smart pointers), or (3) something entirely else is going on here. Which one is it?
Edit: another example
I realized one thing while reading the answers so far: that (1) and (2) are equivalent if (1) includes cases where a type does not implement the Drop trait but "things happen while dropping", which is the case e.g. for a struct that contains another value that implements Drop. I tried this and it is indeed the case (using the CustomSmartPointer from above):
struct Wrapper {
csp: CustomSmartPointer,
}
fn create_wrapper() -> Wrapper {
let pointer = CustomSmartPointer {
data: String::from("my stuff"),
};
Wrapper {
csp: pointer,
}
}
fn main() {
println!("A");
let wrapper = create_wrapper();
println!("B");
println!("output: {}", wrapper.csp.data);
println!("C");
}
This still prints "Dropping CSP" last, after "C", so even a non-Drop wrapper struct that contains a value with the Drop trait has lexical scope. As hinted above, you could then equivalently say: the Drop-able value inside the struct causes a usage at the end of the block that causes the whole wrapper to be dropped only at the end of the block, or you could say that only references have NLL. The difference between the two statements is only about when a value gets dropped that is deeply free of Drop-trait values, which isn't observable.
Do not look if a type implements Drop, look at the return value of needs_drop::<T>() instead.
That said, it is option (1): a type that needs_drop() has an implicit call to drop() at the end of the lexical scope. It is this call that extends the scope of the value.
So you code is as if:
fn main() {
println!("A");
let wrapper = create_wrapper();
println!("B");
println!("output: {}", wrapper.csp.data);
println!("C");
drop(wrapper); // <- implicitly called, wrapper scope ends here
}
Naturally, you can call drop(wrapper) anywhere to end the scope prematurely. As drop() takes its argument by value, it finishes the scope there.
If the type of a value does not needs_drop(), then it is released at the last usage of that value, that is a non lexical scope (NLL).
The non-lexical scopes affects not only references, but any type that doesn't need drop. The thing is that if a value doesn't need drop and doesn't borrow anything, then its scope does not have any visible effect and nobody cares.
For example, this code has a NLL that is technically not a reference:
use std::marker::PhantomData;
#[derive(Debug)]
struct Foo<'a> { _pd: PhantomData<&'a ()> }
impl<'a> Foo<'a> {
fn new<T>(x: &'a mut T) -> Foo<'a> {
Foo { _pd: PhantomData }
}
}
fn main() {
let mut x = 42;
let f1 = Foo::new(&mut x);
let f2 = Foo::new(&mut x);
//dbg!(&f1); // uncomment this line and it will fail to compile
}
It's option two. Implementing Drop trait means that additional actions will happen when object is dropped. But everything will be at some point dropped, whether it implements Drop or not.
println! is not taking your pointer
playgroud...
However, from what I learned I would have expected the last two lines to be swapped. The local variable pointer isn't used anymore after being printed, so I would have expected its scope to end after the line that prints its contents, before "C" gets printed. For example, the section on references has this example:
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// variables r1 and r2 will not be used after this point
let r3 = &mut s; // no problem
println!("{}", r3);
The thing here is that s is never taked, r1 and r2 are dropped after r3 because it takes a mutable reference to s
playground
Can someone explain which exact temporary value is dropped and what the recommended way to do this operation is?
fn main() {
let mut a = &mut String::from("Hello Ownership");
a = &mut a.replace("Ownership", "World");
println!("a is {}", a);
}
If you want to keep the &mut references (which are generally not needed in your case, of course), you can do something like this:
fn main() {
let a = &mut String::from("Hello Ownership");
let a = &mut a.replace("Ownership", "World");
println!("a is {}", a);
}
The type of a would by &mut String. In the second line we do what's known as variable shadowing (not that it's needed) and the type is still &mut String.
That doesn't quite answer your question. I don't know why exactly your version doesn't compile, but at least I thought this info might be useful. (see below)
Update
Thanks to Solomon's findings, I wanted to add that apparently in this case:
let a = &mut ...;
let b = &mut ...;
or this one (variable shadowing, basically the same as the above):
let a = &mut ...;
let a = &mut ...;
, the compiler will automatically extend the lifetime of each temporary until the end of the enclosing block. However, in the case of:
let mut a = &mut ...;
a = &mut ...;
, it seems the compiler simply doesn't do such lifetime extension, so that's why the OP's code doesn't compile, even though the code seems to be doing pretty much the same thing.
Why are you using &mut there? Try this:
fn main() {
let mut a = String::from("Hello Ownership");
a = a.replace("Ownership", "World");
println!("a is {}", a);
}
Aha, figured it out!
https://doc.rust-lang.org/nightly/error-index.html#E0716 says:
Temporaries are not always dropped at the end of the enclosing statement. In simple cases where the & expression is immediately stored into a variable, the compiler will automatically extend the lifetime of the temporary until the end of the enclosing block. Therefore, an alternative way to fix the original program is to write let tmp = &foo() and not let tmp = foo():
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let value = &foo();
let p = bar(value);
let q = *p;
Here, we are still borrowing foo(), but as the borrow is assigned directly into a variable, the temporary will not be dropped until the end of the enclosing block. Similar rules apply when temporaries are stored into aggregate structures like a tuple or struct:
// Here, two temporaries are created, but
// as they are stored directly into `value`,
// they are not dropped until the end of the
// enclosing block.
fn foo() -> i32 { 22 }
let value = (&foo(), &foo());
I am confused with borrowing and ownership. In the Rust documentation about reference and borrowing
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
They say
println! can borrow x.
I am confused by this. If println! borrows x, why does it pass x not &x?
I try to run this code below
fn main() {
let mut x = 5;
{
let y = &mut x;
*y += 1;
}
println!("{}", &x);
}
This code is identical with the code above except I pass &x to println!. It prints '6' to the console which is correct and is the same result as the first code.
The macros print!, println!, eprint!, eprintln!, write!, writeln! and format! are a special case and implicitly take a reference to any arguments to be formatted.
These macros do not behave as normal functions and macros do for reasons of convenience; the fact that they take references silently is part of that difference.
fn main() {
let x = 5;
println!("{}", x);
}
Run it through rustc -Z unstable-options --pretty expanded on the nightly compiler and we can see what println! expands to:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
Tidied further, it’s this:
use std::{fmt, io};
fn main() {
let x = 5;
io::_print(fmt::Arguments::new_v1(
&["", "\n"],
&[fmt::ArgumentV1::new(&x, fmt::Display::fmt)],
// ^^
));
}
Note the &x.
If you write println!("{}", &x), you are then dealing with two levels of references; this has the same result because there is an implementation of std::fmt::Display for &T where T implements Display (shown as impl<'a, T> Display for &'a T where T: Display + ?Sized) which just passes it through. You could just as well write &&&&&&&&&&&&&&&&&&&&&&&x.
Early 2023 update:
Since mid-2021, the required invocation has been rustc -Zunpretty=expanded rather than rustc -Zunstable-options --pretty=expanded.
Since 2023-01-28 or so (https://github.com/rust-lang/rust/pull/106745), format_args! is part of the AST, and so the expansion of println!("{}", x) is ::std::io::_print(format_args!("{0}\n", x));, not exposing the Arguments::new_v1 construction and &x aspects. This is good for various reasons (read #106745’s description), but ruins my clear demonstration here that x was only taken by reference. (This is why I’ve added this as a note at the end rather than updating the answer—since it no longer works.)
In Swift, ! means to unwrap an optional (possible value).
println! is not a function, it is a macro. Macros use ! to distinguish them from normal method calls. The documentation contains more information.
See also:
What is the difference between macros and functions in Rust?
Rust uses the Option type to denote optional data. It has an unwrap method.
Rust 1.13 added the question mark operator ? as an analog of the try! macro (originally proposed via RFC 243).
An excellent explanation of the question mark operator is in The Rust Programming Language.
fn foo() -> Result<i32, Error> {
Ok(4)
}
fn bar() -> Result<i32, Error> {
let a = foo()?;
Ok(a + 4)
}
The question mark operator also extends to Option, so you may see it used to unwrap a value or return None from the function. This is different from just unwrapping as the program will not panic:
fn foo() -> Option<i32> {
None
}
fn bar() -> Option<i32> {
let a = foo()?;
Some(a + 4)
}
println! is a macro in rust, that means that rust will rewrite the code for you at compile time.
For example this:
fn main() {
let x = 5;
println!("{}", x);
}
Will be converted to something like this at compile time:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
let x = 5;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", "\n"],
&match (&x,) {
(arg0,) => [::core::fmt::ArgumentV1::new(
arg0,
::core::fmt::Display::fmt,
)],
},
));
};
}
*Notice that the &x is passed as a reference.
It's a macro because it does things that functions can't do:
It parses the format string at compile time, and generates type safe code
It has a variable number of arguments
It has named arguments ("keyword arguments")
println!("My name is {first} {last}", first = "John", last = "Smith");
sources:
https://doc.rust-lang.org/rust-by-example/hello/print.html.
https://www.reddit.com/r/rust/comments/4qor4o/newb_question_why_is_println_a_macro/
Does println! borrow or own the variable?
Rust tutorials often advocate passing an argument by reference:
fn my_func(x: &Something)
This makes it necessary to explicitly take a reference of the value at the call site:
my_func(&my_value).
It is possible to use the ref keyword usually used in pattern matching:
fn my_func(ref x: Something)
I can call this by doing
my_func(my_value)
Memory-wise, does this work like I expect or does it copy my_value on the stack before calling my_func and then get a reference to the copy?
The value is copied, and the copy is then referenced.
fn f(ref mut x: i32) {
*x = 12;
}
fn main() {
let mut x = 42;
f(x);
println!("{}", x);
}
Output: 42
Both functions declare x to be &Something. The difference is that the former takes a reference as the parameter, while the latter expects it to be a regular stack value. To illustrate:
#[derive(Debug)]
struct Something;
fn by_reference(x: &Something) {
println!("{:?}", x); // prints "&Something""
}
fn on_the_stack(ref x: Something) {
println!("{:?}", x); // prints "&Something""
}
fn main() {
let value_on_the_stack: Something = Something;
let owned: Box<Something> = Box::new(Something);
let borrowed: &Something = &value_on_the_stack;
// Compiles:
on_the_stack(value_on_the_stack);
// Fail to compile:
// on_the_stack(owned);
// on_the_stack(borrowed);
// Dereferencing will do:
on_the_stack(*owned);
on_the_stack(*borrowed);
// Compiles:
by_reference(owned); // Does not compile in Rust 1.0 - editor
by_reference(borrowed);
// Fails to compile:
// by_reference(value_on_the_stack);
// Taking a reference will do:
by_reference(&value_on_the_stack);
}
Since on_the_stack takes a value, it gets copied, then the copy matches against the pattern in the formal parameter (ref x in your example). The match binds x to the reference to the copied value.
If you call a function like f(x) then x is always passed by value.
fn f(ref x: i32) {
// ...
}
is equivalent to
fn f(tmp: i32) {
let ref x = tmp;
// or,
let x = &tmp;
// ...
}
i.e. the referencing is completely restricted to the function call.
The difference between your two functions becomes much more pronounced and obvious if the value doesn't implement Copy. For example, a Vec<T> doesn't implement Copy, because that is an expensive operation, instead, it implements Clone (Which requires a specific method call).
Assume two methods are defined as such
fn take_ref(ref v: Vec<String>) {}// Takes a reference, ish
fn take_addr(v: &Vec<String>) {}// Takes an explicit reference
take_ref will try to copy the value passed, before referencing it. For Vec<T>, this is actually a move operation (Because it doesn't copy). This actually consumes the vector, meaning the following code would throw a compiler error:
let v: Vec<String>; // assume a real value
take_ref(v);// Value is moved here
println!("{:?}", v);// Error, v was moved on the previous line
However, when the reference is explicit, as in take_addr, the Vec isn't moved but passed by reference. Therefore, this code does work as intended:
let v: Vec<String>; // assume a real value
take_addr(&v);
println!("{:?}", v);// Prints contents as you would expect