Extracting a mutable reference from an Option - rust

Is there any option to extract a mutable reference out of an Option<&mut Foo>?
All I found was as_ref() which extracts an immutable reference.

Is there any option to extract a mutable reference outside of a Option<&mut Foo>.
Yes, but it requires a bit of effort to prevent consuming the Option, since &mut T is not Copy.
Let's assume you have an Option<&mut Foo> which is Some. (The same applies for a non-Some option, just replace unwrap() with appropriate matching.) For example:
let mut foo = Foo;
let mut opt = Some(&mut foo);
opt.unwrap() will give you &mut Foo, but it will move it out of the Option, because &mut Foo is not Copy:
let mut_ref = opt.unwrap();
drop(mut_ref); // done with mut_ref
println!("{:?}", opt); // XXX doesn't compile, opt is consumed
That will leave the Option unusable even after mut_ref is out of scope. We don't want that, we want to borrow the inside of the option and retain the use of the Option once that borrow is dropped. For that we can use Option::as_mut:
let mut_ref_ref = opt.as_mut().unwrap();
drop(mut_ref_ref);
println!("{:?}", opt); // compiles
There are two things to note here: first, you need to use as_mut(), not as_ref() as you attempted, because as_ref() would give you a mutable reference behind a shared reference, which renders it useless. Second, unwrapping as_mut() returns an &mut &mut Foo, not the &mut Foo we wanted. It's very close, though - for example, auto-dereferencing allows you to call a function that accepts &mut Foo:
fn wants_ref(_r: &mut Foo) {}
let mut_ref_ref = opt.as_mut().unwrap(); // got &mut &mut Foo
wants_ref(mut_ref_ref); // but we can send it to fn expecting &mut Foo
If you for some reason wanted an actual &mut Foo, one would think you'd get it by dereferencing the &mut &mut Foo. However, this doesn't work:
// XXX doesn't compile
let mut_ref = *opt.as_mut().unwrap();
That doesn't compile because * tries to dereference &mut &mut Foo and extract the underlying &mut Foo. But &mut Foo is not Copy, so that's attempting to "move out of a mutable reference", which rustc will tell you cannot be done. However, in this case it can, you need to perform an explicit reborrow, i.e. turn EXPR to &mut *EXPR, where EXPR evaluates to a mutable reference. &mut *EXPR will create a new mutable reference to the same data. It doesn't count as aliasing because the old mutable reference will be (statically unusable) until the new one is dropped. It's basically the same mechanism that allows projection to work on mutable references (i.e. let x_ref = &mut point.x, with point being an &mut Point) - but applied to the object itself.
With explicit reborrow it looks like this:
// `&mut *` is reborrow, and `*` dereferences `&mut &mut Foo`
let mut_ref = &mut **opt.as_mut().unwrap();
wants_ref(mut_ref);
println!("{:?}", opt); // opt is still usable
Playground

The correct way of doing that is through the as_mut() method.
One tricky bit is that you need to satisfy the &mut self parameter type. The key observation is that if you own a Option<&mut Foo> value, you can safely turn into a mut version of the same (as you are the only owner of it).
That is, you can freely go from a Option<&mut Foo> (owned, immutable) to a mut Option<&mut Foo> (owned, immutable) and call the .as_mut() on that to reach the &mut Foo (reference, mutable).
So overall it looks like this:
let maybe_foo: Option<&mut Foo> = Some(&mut foo);
let mut maybe_foo = maybe_foo;
if let Some(mutable_reference_to_foo) = maybe_foo.as_mut() {
...
}
Playground

Related

function returns immutable references but borrow checker thinks otherwise

Here, I pass some mutable references into a function to perform some action on those. Then, I drop those mutable references by turning them into immutable references. However, the Rust borrow checker still seems to think they are mutable. Here's the code:
//! src/lib.rs
fn append_1_to_all(strings: Vec<&mut String>) -> Vec<&mut String> {
strings.into_iter().map(|s| { s.push_str("1"); s }).collect()
}
fn get_shared_references(strings: Vec<&mut String>) -> Vec<&String> {
strings.into_iter().map(|c| &(*c)).collect()
}
#[test]
fn test() {
let strings = vec!["one".to_string(), "two".to_string(), "three".to_string()];
let strings_appended = append_1_to_all(strings.iter_mut().collect());
let strings_shared = get_shared_references(strings_appended);
assert_ne!(strings[0], *strings_shared[0]);
}
Compile error:
error[E0502]: cannot borrow `strings` as immutable because it is also borrowed as mutable
--> src/lib.rs:16:16
|
12 | let strings_appended = append_1_to_all(strings.iter_mut().collect());
| ------- mutable borrow occurs here
...
16 | assert_ne!(strings[0], *strings_shared[0]);
| ^^^^^^^ -------------- mutable borrow later used here
| |
| immutable borrow occurs here
How can I fix this error? I would think strings_shared shouldn't be related to the mutable borrow anymore.
The problem is not that your reference is actually mutable, but that it's keeping the mutable reference alive.
If you have a reference, type &'a ... or &'a mut ..., and you produce another reference using it, whether that is a reborrow &*some_reference or a field access &some_struct_reference.some_field or a method or anything else, then that is always considered to be a borrow from that original reference, requiring the original reference to live as long as the derived one.
Notice that in your function declaration,
fn get_shared_references(strings: Vec<&mut String>) -> Vec<&String> {...}
if we change it to write out the elided lifetimes, we get this:
fn get_shared_references<'a>(strings: Vec<&'a mut String>) -> Vec<&'a String> {...}
In order to make this work, we'd have to be writing some other lifetime for the result, &'b String instead of `&'a String. But what would that lifetime be, and how is it constrained? It's got to last no longer than the value it refers to does, but be longer than the mutable reference. Rust's lifetime system doesn't have a way to express that. A near miss is:
fn get_shared_references<'m, 'i: 'm>(strings: Vec<&'m mut String>) -> Vec<&'i String> {...}
But even if you could implement a function with this type, it wouldn't be useful to the caller, because they don't know anything about the lifetime 'i other than "at least as long as 'm".
We could imagine a system where mutable references carry two lifetimes — let's suppose the syntax &'m mut 'i T, where 'm is the lifetime for which the reference is mutable, and 'i is (no longer than) the lifetime of the value. In that case, we could possibly have
fn consumes_mut_ref_produces_ref<'m, 'i>(x: &'m mut 'i i32) -> &'i i32 {...}
But a whole new set of lifetime rules would have to be designed to make this work, and it might not even be possible to do consistently. It's certainly not something today's Rust supports.
My recommendation, in the absence of further details on what you're trying to do, would be to make this code to work on owned values. Owned values can be passed around in the way you're trying to do — because taking them as function arguments transfers ownership, so there's no lifetimes to worry about, and it's much more possible to say: "my function consumes this and produces that," with no obligatory relationship.
fn append_1_to_all(mut strings: Vec<String>) -> Vec<String> {
for s in strings.iter_mut() {
s.push_str("1")
}
strings
}
fn get_shared_references(strings: &Vec<String>) -> Vec<&String> {
// Or even better, just use strings.iter() instead of this function
strings.iter().collect()
}
#[test]
fn test() {
let strings = vec!["one".to_string(), "two".to_string(), "three".to_string()];
// .clone() here is necessarily only because strings is used in the assert below
let strings_appended = append_1_to_all(strings.clone());
let strings_shared = get_shared_references(&strings_appended);
assert_ne!(strings[0], *strings_shared[0]);
}

How to bind reference lifetime to a function local scope

I want to write a function A which takes as parameter a function B which takes as parameter a type which is parameterized by a reference type which lifetime is at least the lifetime of the local variables in A’s body.
Consider the following example:
struct Foo {}
fn consume(mut v: Vec<&Foo>) {
while let Some(..) = v.pop() {
// Do stuff
continue;
}
}
fn setup_and<F>(f: F)
where
F: FnOnce(&mut Vec<&Foo>) + Send,
{
let mut v: Vec<&Foo> = vec![];
let other_foo = Foo {};
f(&mut v);
v.push(&other_foo);
consume(v);
}
fn main() {
let foo = Foo {};
setup_and(|v| {
v.push(&foo);
});
}
rustc cannot infer lifetimes on its own. It complains:
error[E0597]: `foo` does not live long enough
--> src/main.rs:25:17
|
24 | setup_and(|v| {
| --- value captured here
25 | v.push(&foo);
| --------^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `foo` is borrowed for `'static`
26 | });
27 | }
| - `foo` dropped here while still borrowed
I tried to specify a lifetime for the reference taken by setup_and like so:
fn setup_and<'a, F>(f: F)
where
F: FnOnce(&mut Vec<&'a Foo>) + Send,
{
let mut v: Vec<&'a Foo> = vec![];
Now rustc complains about the setup_and local reference other_foo not living long enough. I assume it is because it wants a larger lifetime than the scope of setup_and.
How would I bind lifetimes correctly in that case ? I would like to express that the references must be valid until the end of the consume call.
You have a serious, serious issue with conflicting lifetimes in your implementation, and there is no simple fix without at least a partial redesign of the outside signatures of your struct and methods. They all stem from the setup_and method, and are highlighted by the compiler when you explicitly described the lifetime bounds.
The body of your method is copied below, with annotations for you to understand the issue:
let mut v: Vec<&Foo> = vec![];
let other_foo = Foo {}; // other_foo is created here
f(&mut v);
v.push(&other_foo); // other_foo requires lifetime 'a to be added to this
consume(v); // consume does not restrict the lifetime requirement 'a
// other_foo is dropped here, at lifetime less than 'a
The easiest solution to this problem is to store an Arc<Foo>, like so (playground):
fn setup_and<F>(f: F)
where
F: FnOnce(&mut Vec<Arc<Foo>>) + Send,
{
let mut v: Vec<Arc<Foo>> = vec![];
let other_foo = Foo {};
f(&mut v);
v.push(Arc::new(other_foo));
consume(&mut v);
}
Arc is an Atomic Reference-Counting pointer. It is a clonable structure that works as a dynamic pointer to an object on the heap; for all intents and purposes, it works as a read-only reference, without the requirement for a lifetime. When all copies of an Arc are dropped, the item inside it is also dropped.
This solves two problems:
Your other_foo is now moved into the Arc, and no longer causes its lifetime issue
You can now access your objects just like you would a reference (Arc implements Deref)
The choice of Arc was made because your FnOnce requires Send, which Rc (the single-threaded variant of Arc) cannot provide.

Why is `&mut &foo` valid but `&mut a_ref_to_foo` is invalid?

In the following example, t1 compiles but t2 does not.
Is there anything special about &mut &stream? I don't think Deref kicks in.
use std::net::TcpStream;
fn t1() {
let stream = TcpStream::connect("127.0.0.1").unwrap();
let a = &mut &stream;
}
fn t2(stream: &TcpStream) {
let a = &mut stream;
}
Playground
9 | fn t2(stream: &TcpStream) {
| ------ use `mut stream` here to make mutable
10 | let a = &mut stream;
| ^^^^^^ cannot borrow mutably
&mut &foo
This does two things - it creates a temporary value of type &Foo, then creates another temporary of type &mut &Foo.
let a_ref_to_foo = &foo;
&mut a_ref_to_foo
This also creates a temporary of type &mut &Foo, but to something that is observable via the variable binding a_ref_to_foo, not another temporary.
The problem is the same as this example:
// Works
String::new().clear();
// Doesn't work
let s = String::new();
s.clear();
When you have a temporary value, you have ownership over it which includes treating it as mutable. Once it's been assigned to a binding, the binding has ownership and you must indicate that it's allowed to be mutated or not.

Explicit lifetime for Vec to slice conversation

I want a callback on changes inside a list, so I created simple example:
struct Foo;
struct FooList {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(& mut [Foo])>>,
}
impl FooList {
/*
pub fn register_on_change_cb2<F>(&mut self, cb: F) where F: FnMut(&mut [Foo]) {
self.on_change_cb.push(Box::new(cb));
}*/
pub fn register_on_change_cb(&mut self, cb: Box<FnMut(&mut [Foo])>) {
self.on_change_cb.push(cb);
}
pub fn push(&mut self, foo: Foo) {
self.list.push(foo);
self.on_change();
}
fn on_change(&mut self) {
for cb in &mut self.on_change_cb {
cb(&mut self.list);
}
}
}
I don't give any explicit hint to the compiler about lifetimes here: Vec<Box<FnMut(& mut [Foo])>>, so what lifetimes will the compiler use here? If I change the code like this:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&'a mut [Foo])>>,
}
impl<'a> FooList<'a> {
I get a compile time error:
error[E0495]: cannot infer an appropriate lifetime for borrow
expression due to conflicting requirements
How can I explicitly set the lifetimes in some way such that the lifetime of & mut [Foo] for the callback is less than, but not equal to the lifetime of the whole FooList object?
I have commented register_on_change_cb2, I want to allow calling register_on_change_cb without usage of Box::new but failed. If you uncomment register_on_change_cb2, you get the error:
error[E0310]: the parameter type F may not live long enough
How can I fix this error without the requirement of a 'static lifetime for callback? I just want to call Box::new on my side.
I'm going to try to answer your questions 1 and 3, because question 2 is either redundant or orthogonal to the others, and I can't tell what you really want to achieve by it. Perhaps it deserves a question of its own.
If you have a function that takes a reference, but it doesn't need any lifetime information about the reference, it must be able to accept a reference of any lifetime. Here's the explicit syntax for that (this is what the compiler infers from the code you wrote):
on_change_cb: Vec<Box<for<'b> FnMut(&'b mut [Foo])>>,
This is called a higher ranked trait bound or HRTB for short. They're mostly useful for the Fn traits, which is why they exist.
If the type of on_change_cb is Vec<Box<FnMut(&mut [Foo])>>, which doesn't carry any lifetime information, then it must not contain any references (except 'static references). You need to say that the type implementing FnMut may also contain (non-'static) references, as long as they outlive some lifetime 'a:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&mut [Foo]) + 'a>>,
}
This reads something like: "For each FooList object, there is a lifetime 'a such that every callback in the FooList contains only references that live for at least 'a." This interpretation may make it easier to write the prototype for register_on_change_cb2: it takes a callback that also contains only references that live for at least 'a.
impl<'a> FooList<'a> {
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'a
{
self.on_change_cb.push(Box::new(cb));
}
(I think I have the variance of 'a correct now -- a previous version of this answer had it wrong.)
The 'a lifetime lets the compiler guarantee that you never put a callback in the Box (and therefore the Vec) unless it lasts at least as long as the FooList itself. This is important because closures can capture references to values in the enclosing scope, as in the following code (playground link):
let longlived = String::from("hello");
let mut list = FooList {
list: Vec::new(),
on_change_cb: Vec::new(),
};
list.register_on_change_cb2(|_| println!("{}", longlived)); // ok
let shortlived = String::from("hello");
list.register_on_change_cb2(|_| println!("{}", shortlived)); // `shortlived` does not live long enough
list.push(Foo);
In this example, you can't insert the closure that captures shortlived because it doesn't outlive the (inferred) lifetime 'a. But you can insert the closure that captures longlived, because the compiler can infer a lifetime 'a that satisfies both constraints:
'a must outlive list, because list is of type FooList<'a>.
longlived must outlive 'a, because |_| println!("{}", longlived), which borrows longlived, is bounded by 'a in the call to register_on_change_cb2.
If you want to say that the callbacks don't borrow anything by-reference, the 'a lifetime is unnecessary, and in that case you could just add the 'static bound that the compiler suggests:
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'static

What is the idiomatic Rust way to copy/clone a vector in a parameterized function?

I'm trying to write a parameterized function that takes an immutable vector, clones or copies it, does something to the new vector (such as shuffle it) and returns it as a new owned vector. How can this be done and what is the most idiomatic way to do it?
Attempt #1
pub fn shuffle<T>(vec: &mut [T]) {
// ... contents removed: it shuffles the vector in place
// ... so needs a mutable vector
}
pub fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
let mut newvec = vec.clone();
shuffle(&mut newvec);
return newvec.to_owned();
}
Fails with:
error[E0596]: cannot borrow immutable borrowed content as mutable
--> src/main.rs:8:13
|
8 | shuffle(&mut newvec);
| ^^^^^^^^^^^ cannot borrow as mutable
even though I declared newvec as mutable. I don't understand why.
Attempt #2
pub fn shuffle_owned<T: Clone>(mut vec: Vec<T>) -> Vec<T> {
shuffle(&mut vec);
return vec;
}
While this compiles, it doesn't do what I want. The vector you pass into shuffle_owned gets moved into the function, shuffled and then has its ownership transferred back to the caller (via the return value). So the original vector is modified.
I want to know how to pass in a vector that will not be mutated, but have the values cloned into a new boxed vector and returned when finished - as you do in a functional programming language that has immutable data (such as Clojure).
Your attempt #1 is almost correct, you just have to move to_owned() to the first line:
fn shuffle<T>(vec: &mut [T]) {
// ...
}
fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
let mut newvec = vec.to_vec();
shuffle(&mut newvec);
newvec
}
This happens because calling clone() on a slice will return you a slice (i.e. &[T]), and you cannot go from &[T] to &mut [T] because you cannot choose mutability of a reference (borrowed pointer). When you call to_owned(), however, you are getting a fresh instance of Vec<T> and you can put it into a mutable variable to get mutable vector.
As of Rust 1.0, either slice::to_vec or to_owned() method from the ToOwned trait can be used to create Vec<T> from &[T].
There are also now several ways to obtain &mut [T] from Vec<T>: the slicing notation (&mut vec[..]), the deref conversion (&mut *vec) or the direct method call (vec.as_mut_slice(), though this one is deprecated):
This is probably what you want:
pub fn copy_shuffle<T: Clone>(vec: &Vec<T>) -> Vec<T> {
let mut vec = vec.clone();
shuffle(&mut vec);
vec
}
or
pub fn copy_shuffle<T: Clone>(vec: &[T]) -> Vec<T> {
let mut vec = vec.to_vec();
shuffle(&mut vec);
vec
}

Resources