This question already has an answer here:
What is the relation between auto-dereferencing and deref coercion?
(1 answer)
Closed 3 years ago.
Given a rust option:
let mut x = Some(3);
Why can I directly call x.as_mut()? As I can see from the doc, as_mut is defined as:
pub fn as_mut(&mut self) -> Option<&mut T> Converts from &mut
Option to Option<&mut T>.
which expects the first parameter to be &mut self, i.e. &mut Option<T>. Shouldn't I use (&mut x).as_mut() instead?
Here Rust's . operator does what you mean and implicitly borrows the variable. If it didn't, working with non-borrowed values would be annoying, because a value declared as e.g. let mut v = vec![1, 2, 3] couldn't be manipulated with e.g. v.push(4) without writing (&mut v).push(4). The same would apply to fields, so if a struct contained a vector, you'd be unable to call container.vec.push(element) without explicitly borrowing container.vec, even if container itself was itself a mutable reference.
To prevent such noise C has two operators for field access, . and ->, where the latter automatically dereferences. Rust's . intentionally goes ahead and does the borrowing or dereferencing needed for the method call to work.
Related
In this leetcode invert binary tree problem, I'm trying to borrow a node wrapped in an Rc mutably. Here is the code.
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
pub fn invert_tree(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
let mut stack: Vec<Option<Rc<RefCell<TreeNode>>>> = vec![root.clone()];
while stack.len() > 0 {
if let Some(node) = stack.pop().unwrap() {
let n: &mut TreeNode = &mut node.borrow_mut();
std::mem::swap(&mut n.left, &mut n.right);
stack.extend(vec![n.left.clone(), n.right.clone()]);
}
}
root
}
}
If I change the line let n: &mut TreeNode to just let n = &mut node.borrow_mut(), I get a compiler error on the next line, "cannot borrow *n as mutable more than once at a time"
It seems like the compiler infers n to be of type &mut RefMut<TreeNode>, but it all works out when I explicitly say it is &mut TreeNode. Any reason why?
A combination of borrow splitting and deref-coercion causes the seemingly identical code to behave differently.
The compiler infers n to be of type RefMut<TreeNode>, because that's what borrow_mut actually returns:
pub fn borrow_mut(&self) -> RefMut<'_, T>
RefMut is a funny little type that's designed to look like a &mut, but it's actually a separate thing. It implements Deref and DerefMut, so it will happily pretend to be a &mut TreeNode when needed. But Rust is still inserting calls to .deref() in there for you.
Now, why does one work and not the other? Without the type annotation, after deref insertion, you get
let n = &mut node.borrow_mut();
std::mem::swap(&mut n.deref_mut().left, &mut n.deref_mut().right);
So we're trying to call deref_mut (which takes a &mut self) twice in the same line on the same variable. That's not allowed by Rust's borrow rules, so it fails.
(Note that the &mut on the first line simply borrows an owned value for no reason. Temporary lifetime extension lets us get away with this, even though you don't need the &mut at all in this case)
Now, on the other hand, if you do put in the type annotation, then Rust sees that borrow_mut returns a RefMut<'_, TreeNode> but you asked for a &mut TreeNode, so it inserts the deref_mut on the first line. You get
let n: &mut TreeNode = &mut node.borrow_mut().deref_mut();
std::mem::swap(&mut n.left, &mut n.right);
Now the only deref_mut call is on the first line. Then, on the second line, we access n.left and n.right, both mutably, simultaneously. It looks like we're accessing n mutably twice at once, but Rust is actually smart enough to see that we're accessing two disjoint parts of n simultaneously, so it allows it. This is called borrow splitting. Rust will split borrows on different instance fields, but it's not smart enough to see the split across a deref_mut call (function calls could, in principle, do anything, so Rust's borrow checker refuses to try to do advanced reasoning about their return value).
This question already has an answer here:
How to abstract over a reference to a value or a value itself?
(1 answer)
Closed 3 years ago.
Is it possible to represent a generic struct in Rust that can either own or borrow its content? The rough idea is:
struct Foo<T> {
value: T,
}
fn make_foo<'a, T: From<&'a str>>(s: &'a str) -> Foo<T> {
Foo<T>(s.into())
}
However, I don't know how to constrain T so that it can represent either an owned value like a String, or a borrowed value like a &'a str.
Do I have to create two separate FooOwned<T> and FooBorrowed<'a, T>?
std::borrow::Cow
pub enum Cow<'a, B>
where
B: 'a + ToOwned + ?Sized,
{
Borrowed(&'a B),
Owned(<B as ToOwned>::Owned),
}
When you borrow the type, it either returns a reference it stores, or reference to the value it stores, but if you want to borrow from it mutably, it converts to Owned variant, allowing you to take mutable reference to whatever it stores.
Which is why it's named Cow - Copy on Write. It implicitly copies, often in form of clone, whenever you access it in a way that allows writing.
It's not so implicit in a sense that you have to explicitly convert it to Owned, using to_mut, which has this example given to you:
use std::borrow::Cow;
let mut cow = Cow::Borrowed("foo");
cow.to_mut().make_ascii_uppercase();
assert_eq!(
cow,
Cow::Owned(String::from("FOO")) as Cow<str>
);
It's implementation is not as simple, but it's source code is fairly easy to follow, to_mut, which is what you might be interested in, is implemented in line 228.
This question already has answers here:
Why does linking lifetimes matter only with mutable references?
(2 answers)
Closed 4 years ago.
struct A;
fn y<'r>(a: &'r mut Vec<&'r A>) {}
fn x<'r>(a: &'r mut Vec<&'r A>) {
y(a);
y(a);
}
Compilation of this code fails, saying that *a cannot be mutably borrowed second time. When I make the signature look like this (a: &'a mut Vec<&A>), i.e. remove a lifetime from a reference of Vecs content, it compiles just fine.
Why the original code cannot be compiled? I'm unable to see an issue here. For me lifetimes on reference to vector and its content mean just that vector and its content live for the same amount of "time". Where am I wrong?
In this function:
fn y<'r>(a: &'r mut Vec<&'r A>) {}
you are asking that &A has the same lifetime as the (mutable) reference to the Vec. If the reference wasn't mutable, you'd be asking that the lifetime of the &A outlives the reference to the vector, and there wouldn't be a problem. However, mutability makes lifetimes invariant.
Inside this function:
fn x<'r>(a: &'r mut Vec<&'r A>) {
y(a);
y(a);
}
the lifetime of a is the full duration of the function because it's used in every statement. The borrow checker believes (based on the constraint on the lifetimes in y) that y needs the &A for the full lifetime of the vector reference. So the second time you call y, it thinks the reference is still in use.
The reason why removing the explicit lifetimes fixes it is because the borrow checker will infer different lifetimes:
fn y<'r, 's>(a: &'r mut Vec<&'s A>) {}
Now they are not tied together, the borrow checker no longer believes that y needs &A for the whole lifetime of a.
This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
Closed 4 years ago.
I check Index trait in doc and find return type of index() is &T.
Then I write this function to get value from vector:
fn get_value_test(a: usize, v: &Vec<i32>) -> i32 {
v[a]
}
My question is: why v[a] is i32 but &i32? Because i32 ...have a known size at compile time are stored entirely on the stack, so copies of the actual values are quick to make? (from here)
It looks like Rust have hidden rule to convert type in this situation?
There was a small misguidance here. Although the method prototype for Index<Idx> is fn index(&self, index: Idx) -> &T, the syntactical operator x[i] does dereference the output from that &T:
container[index] is actually syntactic sugar for *container.index(index) [...]. This allows nice things such as let value = v[index] if the type of value implements Copy.
So there you go. Your function is indeed returning a copy of the value from the vector, but not from an implicit conversion. If the original intent was to really retrieve a reference to that value, you would do &x[i].
See also:
Meaning of the ampersand '&' and star '*' symbols in Rust
Does Rust automatically dereference primitive type references?
I am looking at the code of Vec<T> to see how it implements iter() as I want to implement iterators for my struct:
pub struct Column<T> {
name: String,
vec: Vec<T>,
...
}
My goal is not to expose the fields and provide iterators to do looping, max, min, sum, avg, etc for a column.
fn test() {
let col: Column<f32> = ...;
let max = col.iter().max();
}
I thought I would see how Vec<T> does iteration. I can see iter() is defined in SliceExt but it's implemented for [T] and not Vec<T> so I am stumped how you can call iter() from Vec<T>?
Indeed, as fjh said, this happens due to how dereference operator functions in Rust and how methods are resolved.
Rust has special Deref trait which allows values of the types implementing it to be "dereferenced" to obtain another type, usually one which is naturally connected to the source type. For example, an implementation like this one:
impl<T> Deref for Vec<T> {
type Target = [T];
fn deref<'a>(&'a self) -> &'a [T] { self.as_slice() }
}
means that applying * unary operator to a Vec<T> would yield [T] which you would need to borrow again:
let v: Vec<u32> = vec![0; 10];
let s: &[u32] = &*v;
(note that even though deref() returns a reference, the dereference operator * returns Target, not &Target - the compiler inserts automatic dereference if you do not borrow the dereferenced value immediately).
This is the first piece of puzzle. The second one is how methods are resolved. Basically, when you write something like
v.iter()
the compiler first tries to find iter() defined on the type of v (in this case Vec<u32>). If no such method can be found, the compiler tries to insert an appropriate number of *s and &s so the method invocation becomes valid. In this case it find that the following is indeed a valid invocation:
(&*v).iter()
Remember, Deref on Vec<T> returns &[T], and slices do have iter() method defined on them. This is also how you can invoke e.g. a method taking &self on a regular value - the compiler automatically inserts a reference operation for you.