I want to destructure a reference to a Copy-type and bind the resulting value mutably. Note: yes, I want to create a copy of the given argument and mutate that copy. This works:
fn foo(a: &u64) {
let mut a = *a;
mutate(&mut a);
}
But I want to do it via destructuring in the argument list. When I just destructure like this:
fn foo(&a: &u64) {
mutate(&mut a);
}
Rust (understandably) complains:
<anon>:3:17: 3:18 error: cannot borrow immutable local variable `a` as mutable
<anon>:3 mutate(&mut a);
^
<anon>:1:9: 1:10 help: to make the local variable mutable, use `mut` as shown:
<anon>: fn foo(&mut a: &u64) {
But the solution the compiler suggests does not work!
<anon>:1:8: 1:14 error: mismatched types:
expected `&u64`,
found `&mut _`
(values differ in mutability) [E0308]
<anon>:1 fn foo(&mut a: &u64) {
^~~~~~
How to do what I want?
I don't think you can do that. While patterns can destructure data (i.e., introduce bindings for parts of data), and bindings can be marked mutable, there doesn't seem to be a way to combine the two in the case of destructuring a reference, even though other combinations work:
struct X(i32);
let it = X(5);
let X(mut inside) = it;
inside = 1;
This may just be an edge case where other syntactic choices leave no good possibility. As you noticed, &mut x is already taken, and disambiguating with parentheses is not supported in patterns.
This isn't a big issue because there are several ways to do the same thing outside the pattern:
Don't make the binding mutable in the pattern and then make a new, mutable binding (let mut x = x;)
Don't destructure to begin with ‐ it's not terribly useful with references since you can just say let mut x = *reference;.
Trying to be too clever in argument lists is detrimental to readability anyway IMHO.
This seems to work on the Rust playground:
fn foo(mut a: &mut u64) {
mutate(a);
}
Short answer is that you need to take in a mutable parameter that has the type of a mutable reference to a u64. I cannot provide a better answer, I'm still learning.
Here you can see a working example: Rust Playground
I am not 100% sure if I understand what you're asking, but it's worth a shot.
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).
I'm trying to modify the borrow of a mutable value, here is a minimal example:
fn main() {
let mut w: [char; 5] = ['h', 'e', 'l', 'l', 'o'];
let mut wslice: &mut [char] = &mut w;
advance_slice(&mut wslice);
advance_slice(&mut wslice);
}
fn advance_slice(s: &mut &mut [char]) {
let new: &mut [char] = &mut s[1..];
*s = new;
}
the compiler gives me this error:
error[E0623]: lifetime mismatch
--> src/main.rs:10:10
|
8 | fn advance_slice(s: &mut &mut [char]) {
| ----------------
| |
| these two types are declared with different lifetimes...
9 | let new: &mut [char] = &mut s[1..];
10 | *s = new;
| ^^^ ...but data from `s` flows into `s` here
I've tried to give the same lifetime to both borrow, without success.
Also this works if I remove the mutability of w.
This error message is indeed unfortunate, and I don't think it provides a good explanation of what's going on here. The issue is a bit involved.
The error is local to the advance_slice() function, so that's all we need to look at. The type of the slice items is irrelevant, so let's take this function definition:
fn advance_slice_mut<T>(s: &mut &mut [T]) {
let new = &mut s[1..];
*s = new;
}
The first line creates a new slice object starting after the first item of the original slice.
Why is this even allowed? Don't we have two mutable references to the same data now? The original slice *s includes the new slice new, and both allow modifying data. The reason this is legal is that *s is implicitly reborrowed when creating the subslice, and *s cannot be used again for the lifetime of that borrow, so we still have only one active reference to the data in the subslice. The reborrow is scoped to the function advance_slice_mut(), and thus has a shorter lifetime than the original slice, which is the root cause of the error you get – you are effectively trying to assign a slice which only lives until the end of the function to a memory location that lives longer than the function call.
This kind of implicit reborrow happens everytime you call a function that takes an argument by mutable reference, including in the implicit call to index_mut() in &mut s[1..]. Mutable references can't be copied, since this would create two mutable references to the same memory, and the Rust language designers decided that an implicit reborrow is the more ergonomic solution than moving mutable references by default. The reborrow does not happen for shared references, though, since they can be freely copied. This means that &s[1..] will have the same lifetime as the original scope, since it is perfectly fine for two overlapping immutable slices to coexist. This explains why your function definition works fine for immutable slices.
So how do we fix this problem? I believe that what you intend to do is perfectly safe – after reassigning the new slice to the old one, the old one is gone, so we don't have two concurrent mutable references to the same memory. To create a slice with the same lifetime as the original slice in safe code, we need to move the original slice out of the reference we got. We can do this by replacing it with an empty slice:
pub fn advance_slice_mut<T>(s: &mut &mut [T]) {
let slice = std::mem::replace(s, &mut []);
*s = &mut slice[1..];
}
Alternatively, we can also resort to unsafe code:
use std::slice::from_raw_parts_mut;
pub fn advance_slice_mut<T>(s: &mut &mut [T]) {
unsafe {
assert!(!s.is_empty());
*s = from_raw_parts_mut(s.as_mut_ptr().add(1), s.len() - 1);
}
}
This code fails the dreaded borrow checker (playground):
struct Data {
a: i32,
b: i32,
c: i32,
}
impl Data {
fn reference_to_a(&mut self) -> &i32 {
self.c = 1;
&self.a
}
fn get_b(&self) -> i32 {
self.b
}
}
fn main() {
let mut dat = Data{ a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
println!("{}", dat.get_b());
}
Since non-lexical lifetimes were implemented, this is required to trigger the error:
fn main() {
let mut dat = Data { a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
let b = dat.get_b();
println!("{:?}, {}", aref, b);
}
Error:
error[E0502]: cannot borrow `dat` as immutable because it is also borrowed as mutable
--> <anon>:19:20
|
18 | let aref = dat.reference_to_a();
| --- mutable borrow occurs here
19 | println!("{}", dat.get_b());
| ^^^ immutable borrow occurs here
20 | }
| - mutable borrow ends here
Why is this? I would have thought that the mutable borrow of dat is converted into an immutable one when reference_to_a() returns, because that function only returns an immutable reference. Is the borrow checker just not clever enough yet? Is this planned? Is there a way around it?
Lifetimes are separate from whether a reference is mutable or not. Working through the code:
fn reference_to_a(&mut self) -> &i32
Although the lifetimes have been elided, this is equivalent to:
fn reference_to_a<'a>(&'a mut self) -> &'a i32
i.e. the input and output lifetimes are the same. That's the only way to assign lifetimes to a function like this (unless it returned an &'static reference to global data), since you can't make up the output lifetime from nothing.
That means that if you keep the return value alive by saving it in a variable, you're keeping the &mut self alive too.
Another way of thinking about it is that the &i32 is a sub-borrow of &mut self, so is only valid until that expires.
As #aSpex points out, this is covered in the nomicon.
Why is this an error: While a more precise explanation was already given by #Chris some 2.5 years ago, you can read fn reference_to_a(&mut self) -> &i32 as a declaration that:
“I want to exclusively borrow self, then return a shared/immutable reference which lives as long as the original exclusive borrow” (source)
Apparently it can even prevent me from shooting myself in the foot.
Is the borrow checker just not clever enough yet? Is this planned?
There's still no way to express "I want to exclusively borrow self for the duration of the call, and return a shared reference with a separate lifetime". It is mentioned in the nomicon as #aSpex pointed out, and is listed among the Things Rust doesn’t let you do as of late 2018.
I couldn't find specific plans to tackle this, as previously other borrow checker improvements were deemed higher priority. The idea about allowing separate read/write "lifetime roles" (Ref2<'r, 'w>) was mentioned in the NLL RFC, but no-one has made it into an RFC of its own, as far as I can see.
Is there a way around it? Not really, but depending on the reason you needed this in the first place, other ways of structuring the code may be appropriate:
You can return a copy/clone instead of the reference
Sometimes you can split a fn(&mut self) -> &T into two, one taking &mut self and another returning &T, as suggested by #Chris here
As is often the case in Rust, rearranging your structs to be "data-oriented" rather than "object-oriented" can help
You can return a shared reference from the method: fn(&mut self) -> (&Self, &T) (from this answer)
You can make the fn take a shared &self reference and use interior mutability (i.e. define the parts of Self that need to be mutated as Cell<T> or RefCell<T>). This may feel like cheating, but it's actually appropriate, e.g. when the reason you need mutability as an implementation detail of a logically-immutable method. After all we're making a method take a &mut self not because it mutates parts of self, but to make it known to the caller so that it's possible to reason about which values can change in a complex program.
I'm trying to understand how HashMaps work in Rust and I have come up with this example.
use std::collections::HashMap;
fn main() {
let mut roman2number: HashMap<&'static str, i32> = HashMap::new();
roman2number.insert("X", 10);
roman2number.insert("I", 1);
let roman_num = "XXI".to_string();
let r0 = roman_num.chars().take(1).collect::<String>();
let r1: &str = &r0.to_string();
println!("{:?}", roman2number.get(r1)); // This works
// println!("{:?}", roman2number.get(&r0.to_string())); // This doesn't
}
When I try to compile the code with last line uncommented, I get the following error
error: the trait bound `&str: std::borrow::Borrow<std::string::String>` is not satisfied [E0277]
println!("{:?}", roman2number.get(&r0.to_string()));
^~~
note: in this expansion of format_args!
note: in this expansion of print! (defined in <std macros>)
note: in this expansion of println! (defined in <std macros>)
help: run `rustc --explain E0277` to see a detailed explanation
The Trait implementation section of the docs gives the dereferencing as fn deref(&self) -> &str
So what is happening here?
The error is caused by that generic function HashMap::get over String is selected by the compiler during type inference. But you want HashMap::get over str.
So just change
println!("{:?}", roman2number.get(&r0.to_string()));
to
println!("{:?}", roman2number.get::<str>(&r0.to_string()));
to make it explicit. This helps the compiler to select the right function.
Check out Playground here.
It looks to me that coercion Deref<Target> can only happen when we know the target type, so when compiler is trying to infer which HashMap::get to use, it sees &r0.to_string() as type &String but never &str. And &'static str does not implement Borrow<String>. This results a type error. When we specify HashMap::get::<str>, this function expects &str, when coercion can be applied to &String to get a matching &str.
You can check out Deref coercion and String Deref for more details.
The other answers are correct, but I wanted to point out that you have an unneeded to_string (you've already collected into a String) and an alternate way of coercing to a &str, using as:
let r0: String = roman_num.chars().take(1).collect();
println!("{:?}", roman2number.get(&r0 as &str));
In this case, I'd probably just rewrite the map to contain char as the key though:
use std::collections::HashMap;
fn main() {
let mut roman2number = HashMap::new();
roman2number.insert('X', 10);
roman2number.insert('I', 1);
let roman_num = "XXI";
for c in roman_num.chars() {
println!("{:?}", roman2number.get(&c));
}
}
Note there's no need to have an explicit type for the map, it will be inferred.
The definition of the get method looks as follows
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
The first part is the type of object which you pass: Q. There are constraints on Q. The conditions on Q are that
the key-type K needs to implement the Borrow trait over Q
Q needs to implement the Hash and Eq traits.
Replacing this with your actual types means that the key-type &'static str needs to implement Borrow<String>. By the definition of Borrow, this means that a &'static str needs to be convertible to &String. But all the docs/texts I've read state that everywhere you'd use &String you should be using &str instead. So it makes little sense to offer a &str -> &String conversion, even if it would make life a little easier sometimes.
Since every reference type is borrowable as a shorter lived reference type.), you can pass a &str when a &'static str is the key-type, because &'static str implements Borrow<str>
I was reading the lifetimes chapter of the Rust book, and I came across this example for a named/explicit lifetime:
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
} // -+ x goes out of scope
It's quite clear to me that the error being prevented by the compiler is the use-after-free of the reference assigned to x: after the inner scope is done, f and therefore &f.x become invalid, and should not have been assigned to x.
My issue is that the problem could have easily been analyzed away without using the explicit 'a lifetime, for instance by inferring an illegal assignment of a reference to a wider scope (x = &f.x;).
In which cases are explicit lifetimes actually needed to prevent use-after-free (or some other class?) errors?
The other answers all have salient points (fjh's concrete example where an explicit lifetime is needed), but are missing one key thing: why are explicit lifetimes needed when the compiler will tell you you've got them wrong?
This is actually the same question as "why are explicit types needed when the compiler can infer them". A hypothetical example:
fn foo() -> _ {
""
}
Of course, the compiler can see that I'm returning a &'static str, so why does the programmer have to type it?
The main reason is that while the compiler can see what your code does, it doesn't know what your intent was.
Functions are a natural boundary to firewall the effects of changing code. If we were to allow lifetimes to be completely inspected from the code, then an innocent-looking change might affect the lifetimes, which could then cause errors in a function far away. This isn't a hypothetical example. As I understand it, Haskell has this problem when you rely on type inference for top-level functions. Rust nipped that particular problem in the bud.
There is also an efficiency benefit to the compiler — only function signatures need to be parsed in order to verify types and lifetimes. More importantly, it has an efficiency benefit for the programmer. If we didn't have explicit lifetimes, what does this function do:
fn foo(a: &u8, b: &u8) -> &u8
It's impossible to tell without inspecting the source, which would go against a huge number of coding best practices.
by inferring an illegal assignment of a reference to a wider scope
Scopes are lifetimes, essentially. A bit more clearly, a lifetime 'a is a generic lifetime parameter that can be specialized with a specific scope at compile time, based on the call site.
are explicit lifetimes actually needed to prevent [...] errors?
Not at all. Lifetimes are needed to prevent errors, but explicit lifetimes are needed to protect what little sanity programmers have.
Let's have a look at the following example.
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
x
}
fn main() {
let x = 12;
let z: &u32 = {
let y = 42;
foo(&x, &y)
};
}
Here, the explicit lifetimes are important. This compiles because the result of foo has the same lifetime as its first argument ('a), so it may outlive its second argument. This is expressed by the lifetime names in the signature of foo. If you switched the arguments in the call to foo the compiler would complain that y does not live long enough:
error[E0597]: `y` does not live long enough
--> src/main.rs:10:5
|
9 | foo(&y, &x)
| - borrow occurs here
10 | };
| ^ `y` dropped here while still borrowed
11 | }
| - borrowed value needs to live until here
The lifetime annotation in the following structure:
struct Foo<'a> {
x: &'a i32,
}
specifies that a Foo instance shouldn't outlive the reference it contains (x field).
The example you came across in the Rust book doesn't illustrate this because f and y variables go out of scope at the same time.
A better example would be this:
fn main() {
let f : Foo;
{
let n = 5; // variable that is invalid outside this block
let y = &n;
f = Foo { x: y };
};
println!("{}", f.x);
}
Now, f really outlives the variable pointed to by f.x.
Note that there are no explicit lifetimes in that piece of code, except the structure definition. The compiler is perfectly able to infer lifetimes in main().
In type definitions, however, explicit lifetimes are unavoidable. For example, there is an ambiguity here:
struct RefPair(&u32, &u32);
Should these be different lifetimes or should they be the same? It does matter from the usage perspective, struct RefPair<'a, 'b>(&'a u32, &'b u32) is very different from struct RefPair<'a>(&'a u32, &'a u32).
Now, for simple cases, like the one you provided, the compiler could theoretically elide lifetimes like it does in other places, but such cases are very limited and do not worth extra complexity in the compiler, and this gain in clarity would be at the very least questionable.
If a function receives two references as arguments and returns a reference, then the implementation of the function might sometimes return the first reference and sometimes the second one. It is impossible to predict which reference will be returned for a given call. In this case, it is impossible to infer a lifetime for the returned reference, since each argument reference may refer to a different variable binding with a different lifetime. Explicit lifetimes help to avoid or clarify such a situation.
Likewise, if a structure holds two references (as two member fields) then a member function of the structure may sometimes return the first reference and sometimes the second one. Again explicit lifetimes prevent such ambiguities.
In a few simple situations, there is lifetime elision where the compiler can infer lifetimes.
I've found another great explanation here: http://doc.rust-lang.org/0.12.0/guide-lifetimes.html#returning-references.
In general, it is only possible to return references if they are
derived from a parameter to the procedure. In that case, the pointer
result will always have the same lifetime as one of the parameters;
named lifetimes indicate which parameter that is.
The case from the book is very simple by design. The topic of lifetimes is deemed complex.
The compiler cannot easily infer the lifetime in a function with multiple arguments.
Also, my own optional crate has an OptionBool type with an as_slice method whose signature actually is:
fn as_slice(&self) -> &'static [bool] { ... }
There is absolutely no way the compiler could have figured that one out.
As a newcomer to Rust, my understanding is that explicit lifetimes serve two purposes.
Putting an explicit lifetime annotation on a function restricts the type of code that may appear inside that function. Explicit lifetimes allow the compiler to ensure that your program is doing what you intended.
If you (the compiler) want(s) to check if a piece of code is valid, you (the compiler) will not have to iteratively look inside every function called. It suffices to have a look at the annotations of functions that are directly called by that piece of code. This makes your program much easier to reason about for you (the compiler), and makes compile times managable.
On point 1., Consider the following program written in Python:
import pandas as pd
import numpy as np
def second_row(ar):
return ar[0]
def work(second):
df = pd.DataFrame(data=second)
df.loc[0, 0] = 1
def main():
# .. load data ..
ar = np.array([[0, 0], [0, 0]])
# .. do some work on second row ..
second = second_row(ar)
work(second)
# .. much later ..
print(repr(ar))
if __name__=="__main__":
main()
which will print
array([[1, 0],
[0, 0]])
This type of behaviour always surprises me. What is happening is that df is sharing memory with ar, so when some of the content of df changes in work, that change infects ar as well. However, in some cases this may be exactly what you want, for memory efficiency reasons (no copy). The real problem in this code is that the function second_row is returning the first row instead of the second; good luck debugging that.
Consider instead a similar program written in Rust:
#[derive(Debug)]
struct Array<'a, 'b>(&'a mut [i32], &'b mut [i32]);
impl<'a, 'b> Array<'a, 'b> {
fn second_row(&mut self) -> &mut &'b mut [i32] {
&mut self.0
}
}
fn work(second: &mut [i32]) {
second[0] = 1;
}
fn main() {
// .. load data ..
let ar1 = &mut [0, 0][..];
let ar2 = &mut [0, 0][..];
let mut ar = Array(ar1, ar2);
// .. do some work on second row ..
{
let second = ar.second_row();
work(second);
}
// .. much later ..
println!("{:?}", ar);
}
Compiling this, you get
error[E0308]: mismatched types
--> src/main.rs:6:13
|
6 | &mut self.0
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `&mut &'b mut [i32]`
found type `&mut &'a mut [i32]`
note: the lifetime 'b as defined on the impl at 4:5...
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 4:5
--> src/main.rs:4:5
|
4 | impl<'a, 'b> Array<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
In fact you get two errors, there is also one with the roles of 'a and 'b interchanged. Looking at the annotation of second_row, we find that the output should be &mut &'b mut [i32], i.e., the output is supposed to be a reference to a reference with lifetime 'b (the lifetime of the second row of Array). However, because we are returning the first row (which has lifetime 'a), the compiler complains about lifetime mismatch. At the right place. At the right time. Debugging is a breeze.
The reason why your example does not work is simply because Rust only has local lifetime and type inference. What you are suggesting demands global inference. Whenever you have a reference whose lifetime cannot be elided, it must be annotated.
I think of a lifetime annotation as a contract about a given ref been valid in the receiving scope only while it remains valid in the source scope. Declaring more references in the same lifetime kind of merges the scopes, meaning that all the source refs have to satisfy this contract.
Such annotation allow the compiler to check for the fulfillment of the contract.