Why is this a &str in Rust [duplicate] - rust

It is possible to make the following binding in Rust:
let &mut a = &mut 5;
But what does it mean exactly? For example, let a = &mut 5 creates an immutable binding of type &mut i32, let mut a = &mut 5 creates a mutable binding of type &mut i32. What about let &mut?

An easy way to test the type of something is to assign it to the wrong type:
let _: () = a;
In this case the value is an "integral variable", or a by-value integer. It is not mutable (as testing with a += 1 shows).
This is because you are using destructuring syntax. You are pattern matching your &mut 5 against an &mut _, much like if you wrote
match &mut 5 { &mut a => {
// rest of code
} };
Thus you are adding a mutable reference and immediately dereferencing it.
To bind a mutable reference to a value instead, you can do
let ref mut a = 5;
This is useful in destructuring to take references to multiple inner values.

Related

Rust - borrowed value does not live long enough [duplicate]

I want to write a program that will write a file in 2 steps.
It is likely that the file may not exist before the program is run. The filename is fixed.
The problem is that OpenOptions.new().write() can fail. In that case, I want to call a custom function trycreate(). The idea is to create the file instead of opening it and return a handle. Since the filename is fixed, trycreate() has no arguments and I cannot set a lifetime of the returned value.
How can I resolve this problem?
use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
fn trycreate() -> &OpenOptions {
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("ERR"),
};
f
}
fn main() {
{
let f = OpenOptions::new().write(true).open(b"foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => trycreate("foo.txt"),
};
let buf = b"test1\n";
let _ret = f.write(buf).unwrap();
}
println!("50%");
{
let f = OpenOptions::new().append(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("append"),
};
let buf = b"test2\n";
let _ret = f.write(buf).unwrap();
}
println!("Ok");
}
The question you asked
TL;DR: No, you cannot return a reference to a variable that is owned by a function. This applies if you created the variable or if you took ownership of the variable as a function argument.
Solutions
Instead of trying to return a reference, return an owned object. String instead of &str, Vec<T> instead of &[T], T instead of &T, etc.
If you took ownership of the variable via an argument, try taking a (mutable) reference instead and then returning a reference of the same lifetime.
In rare cases, you can use unsafe code to return the owned value and a reference to it. This has a number of delicate requirements you must uphold to ensure you don't cause undefined behavior or memory unsafety.
See also:
Proper way to return a new string in Rust
Return local String as a slice (&str)
Why can't I store a value and a reference to that value in the same struct?
Deeper answer
fjh is absolutely correct, but I want to comment a bit more deeply and touch on some of the other errors with your code.
Let's start with a smaller example of returning a reference and look at the errors:
fn try_create<'a>() -> &'a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<'a>() -> &'a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Is there any way to return a reference from a function without arguments?
Technically "yes", but for what you want, "no".
A reference points to an existing piece of memory. In a function with no arguments, the only things that could be referenced are global constants (which have the lifetime &'static) and local variables. I'll ignore globals for now.
In a language like C or C++, you could actually take a reference to a local variable and return it. However, as soon as the function returns, there's no guarantee that the memory that you are referencing continues to be what you thought it was. It might stay what you expect for a while, but eventually the memory will get reused for something else. As soon as your code looks at the memory and tries to interpret a username as the amount of money left in the user's bank account, problems will arise!
This is what Rust's lifetimes prevent - you aren't allowed to use a reference beyond how long the referred-to value is valid at its current memory location.
See also:
Is it possible to return either a borrowed or owned type in Rust?
Why can I return a reference to a local literal but not a variable?
Your actual problem
Look at the documentation for OpenOptions::open:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
It returns a Result<File>, so I don't know how you'd expect to return an OpenOptions or a reference to one. Your function would work if you rewrote it as:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn't open")
}
This uses Result::expect to panic with a useful error message. Of course, panicking in the guts of your program isn't super useful, so it's recommended to propagate your errors back out:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option and Result have lots of nice methods to deal with chained error logic. Here, you can use or_else:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
I'd also return the Result from main. All together, including fjh's suggestions:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1\n")?;
f.write_all(b"test2\n")?;
Ok(())
}
Is there any way to return a reference from a function without arguments?
No (except references to static values, but those aren't helpful here).
However, you might want to look at OpenOptions::create. If you change your first line in main to
let f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
the file will be created if it does not yet exist, which should solve your original problem.
You can not return a reference pointing to a local variable. You have two alternatives, either return the value or use a static variable.
Here is why:
References are pointers to memory locations. Once functions are executed, local variables are popped off the execution stack and resources are de-allocated. After that point, any reference to a local variable will be pointing to some useless data. Since it is de-allocated, it is not in our program's possession any more and OS may have already given it to another process and our data may have been overwritten.
For the following example, x is created when the function runs and dropped off when the function completes executing. It is local to the function and lives on this particular function's stack. Function's stack holds local variables.
When run is pop off the execution stack, any reference to x, &x, will be pointing to some garbage data. That is what people call a dangling pointer. The Rust compiler does not allow to use dangling pointers since it is not safe.
fn run() -> &u32 {
let x: u32 = 42;
return &x;
} // x is dropped here
fn main() {
let x = run();
}
So, that is why we can not return a reference to a local variable. We have two options: either return the value or use a static variable.
Returning the value is the best option here. By returning the value, you will be passing the result of your calculation to the caller, in Rust's terms x will be owned by the caller. In our case it is main. So, no problem there.
Since a static variable lives as long as the process runs, its references will be pointing to the same memory location both inside and outside the function. No problem there either.
Note: #navigaid advises using a box, but it does not make sense because you are moving readily available data to heap by boxing it and then returning it. It does not solve the problem, you are still returning the local variable to the caller but using a pointer when accessing it. It adds an unnecessary indirection due to de-referencing hence incurring additional cost. Basically you will be using & for the sake of using it, nothing more.
This is an elaboration on snnsnn's answer, which briefly explained the problem without being too specific.
Rust doesn't allow return a reference to a variable created in a function. Is there a workaround? Yes, simply put that variable in a Box then return it. Example:
fn run() -> Box<u32> {
let x: u32 = 42;
return Box::new(x);
}
fn main() {
println!("{}", run());
}
code in rust playground
As a rule of thumb, to avoid similar problems in Rust, return an owned object (Box, Vec, String, ...) instead of reference to a variable:
Box<T> instead of &T
Vec<T> instead of &[T]
String instead of &str
For other types, refer to The Periodic Table of Rust Types to figure out which owned object to use.
Of course, in this example you can simply return the value (T instead of &T or Box<T>)
fn run() -> u32 {
let x: u32 = 42;
return x;
}
Yes! But you have to find a way to extend the lifetime. One way to do that is to provide mutable reference to a dummy/default value (&mut T) to the function and then fill/replace the value in the function and then return a reference to that value (&T). This way you can specify the lifetime so that the returned reference get the lifetime of a value outside the function.
Examples:
//&mut T -> &T
fn example2<'a>(life: &'a mut Vec<i32>) -> &'a Vec<i32> {
*life = vec![1, 2, 3, 4];
life
}
fn test_example2() {
//Could also use Vec::new()
let mut life = Vec::default();
let res = example2(&mut life);
println!("{:?}", res)
}
fn test2_example2() {
let life = &mut Vec::default();
let res = example2(life);
println!("{:?}", res)
}
//shows real use case
fn get_check_test_slices2<'a>(
lifetime: &'a mut Vec<usize>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
// create a list of primes using a simple primes sieve
*lifetime = primes1_iter_bitvec(limit).collect::<Vec<_>>();
// iterate through pairs of sub slices without copying the primes vec
// slices will be used to check that a complicated sieve is correct
all_test_check_slices(lifetime)
}
Edit:
How is that different from just giving &mut T to the function? (asked by Chayim Friedman (see old solution below)):
It's basically the same... I lost against the borrow checker previously, and that is why I didn't just use &mut T. But after renewed battles I have finally managed to just use &mut T. Thank you for the insightful question.
Old solution:
My solution works by creating a default value before calling the function, which the function later replaces/fills and returns a reference to.
/// Used to return references to values created in a function.
/// fn example<'a>(lt:& 'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
/// lt.set(vec![1,2,3,4]);
/// lt.get()
/// }
pub struct LifeExtender<T> {
value: T,
}
impl<T> Default for LifeExtender<T>
where
T: Default,
{
/// using T default.
fn default() -> Self {
Self {
value: T::default(),
}
}
}
impl<T> LifeExtender<T> {
/// If T doesn't have default.
pub fn new(value: T) -> Self {
Self { value }
}
/// set value to be returned by reference
pub fn set(&mut self, new_value: T) {
self.value = new_value;
}
/// Get a reference with lifetime self.
pub fn get<'a>(&'a self) -> &'a T {
&self.value
}
/// Get a mut reference with lifetime self.
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.value
}
}
fn example<'a>(life: &'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
let local_value = vec![1, 2, 3, 4];
life.set(local_value);
life.get()
}
//prints: [1,2,3,4]
pub fn test_example() {
let mut life = LifeExtender::default();
let res = example(&mut life);
println!("{:?}", res);
}
//Real example code snippet, where I used this solution:
fn get_check_slices2<'a>(
lifetime: &'a mut LifeExtender<Vec<usize>>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
lifetime.set(primes1_iter_bitvec(limit).collect::<Vec<_>>());
all_test_check_slices(lifetime.get())
}

How to fix "returns a value referencing data owned by the current function" in Rust [duplicate]

I want to write a program that will write a file in 2 steps.
It is likely that the file may not exist before the program is run. The filename is fixed.
The problem is that OpenOptions.new().write() can fail. In that case, I want to call a custom function trycreate(). The idea is to create the file instead of opening it and return a handle. Since the filename is fixed, trycreate() has no arguments and I cannot set a lifetime of the returned value.
How can I resolve this problem?
use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
fn trycreate() -> &OpenOptions {
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("ERR"),
};
f
}
fn main() {
{
let f = OpenOptions::new().write(true).open(b"foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => trycreate("foo.txt"),
};
let buf = b"test1\n";
let _ret = f.write(buf).unwrap();
}
println!("50%");
{
let f = OpenOptions::new().append(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("append"),
};
let buf = b"test2\n";
let _ret = f.write(buf).unwrap();
}
println!("Ok");
}
The question you asked
TL;DR: No, you cannot return a reference to a variable that is owned by a function. This applies if you created the variable or if you took ownership of the variable as a function argument.
Solutions
Instead of trying to return a reference, return an owned object. String instead of &str, Vec<T> instead of &[T], T instead of &T, etc.
If you took ownership of the variable via an argument, try taking a (mutable) reference instead and then returning a reference of the same lifetime.
In rare cases, you can use unsafe code to return the owned value and a reference to it. This has a number of delicate requirements you must uphold to ensure you don't cause undefined behavior or memory unsafety.
See also:
Proper way to return a new string in Rust
Return local String as a slice (&str)
Why can't I store a value and a reference to that value in the same struct?
Deeper answer
fjh is absolutely correct, but I want to comment a bit more deeply and touch on some of the other errors with your code.
Let's start with a smaller example of returning a reference and look at the errors:
fn try_create<'a>() -> &'a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<'a>() -> &'a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Is there any way to return a reference from a function without arguments?
Technically "yes", but for what you want, "no".
A reference points to an existing piece of memory. In a function with no arguments, the only things that could be referenced are global constants (which have the lifetime &'static) and local variables. I'll ignore globals for now.
In a language like C or C++, you could actually take a reference to a local variable and return it. However, as soon as the function returns, there's no guarantee that the memory that you are referencing continues to be what you thought it was. It might stay what you expect for a while, but eventually the memory will get reused for something else. As soon as your code looks at the memory and tries to interpret a username as the amount of money left in the user's bank account, problems will arise!
This is what Rust's lifetimes prevent - you aren't allowed to use a reference beyond how long the referred-to value is valid at its current memory location.
See also:
Is it possible to return either a borrowed or owned type in Rust?
Why can I return a reference to a local literal but not a variable?
Your actual problem
Look at the documentation for OpenOptions::open:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
It returns a Result<File>, so I don't know how you'd expect to return an OpenOptions or a reference to one. Your function would work if you rewrote it as:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn't open")
}
This uses Result::expect to panic with a useful error message. Of course, panicking in the guts of your program isn't super useful, so it's recommended to propagate your errors back out:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option and Result have lots of nice methods to deal with chained error logic. Here, you can use or_else:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
I'd also return the Result from main. All together, including fjh's suggestions:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1\n")?;
f.write_all(b"test2\n")?;
Ok(())
}
Is there any way to return a reference from a function without arguments?
No (except references to static values, but those aren't helpful here).
However, you might want to look at OpenOptions::create. If you change your first line in main to
let f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
the file will be created if it does not yet exist, which should solve your original problem.
You can not return a reference pointing to a local variable. You have two alternatives, either return the value or use a static variable.
Here is why:
References are pointers to memory locations. Once functions are executed, local variables are popped off the execution stack and resources are de-allocated. After that point, any reference to a local variable will be pointing to some useless data. Since it is de-allocated, it is not in our program's possession any more and OS may have already given it to another process and our data may have been overwritten.
For the following example, x is created when the function runs and dropped off when the function completes executing. It is local to the function and lives on this particular function's stack. Function's stack holds local variables.
When run is pop off the execution stack, any reference to x, &x, will be pointing to some garbage data. That is what people call a dangling pointer. The Rust compiler does not allow to use dangling pointers since it is not safe.
fn run() -> &u32 {
let x: u32 = 42;
return &x;
} // x is dropped here
fn main() {
let x = run();
}
So, that is why we can not return a reference to a local variable. We have two options: either return the value or use a static variable.
Returning the value is the best option here. By returning the value, you will be passing the result of your calculation to the caller, in Rust's terms x will be owned by the caller. In our case it is main. So, no problem there.
Since a static variable lives as long as the process runs, its references will be pointing to the same memory location both inside and outside the function. No problem there either.
Note: #navigaid advises using a box, but it does not make sense because you are moving readily available data to heap by boxing it and then returning it. It does not solve the problem, you are still returning the local variable to the caller but using a pointer when accessing it. It adds an unnecessary indirection due to de-referencing hence incurring additional cost. Basically you will be using & for the sake of using it, nothing more.
This is an elaboration on snnsnn's answer, which briefly explained the problem without being too specific.
Rust doesn't allow return a reference to a variable created in a function. Is there a workaround? Yes, simply put that variable in a Box then return it. Example:
fn run() -> Box<u32> {
let x: u32 = 42;
return Box::new(x);
}
fn main() {
println!("{}", run());
}
code in rust playground
As a rule of thumb, to avoid similar problems in Rust, return an owned object (Box, Vec, String, ...) instead of reference to a variable:
Box<T> instead of &T
Vec<T> instead of &[T]
String instead of &str
For other types, refer to The Periodic Table of Rust Types to figure out which owned object to use.
Of course, in this example you can simply return the value (T instead of &T or Box<T>)
fn run() -> u32 {
let x: u32 = 42;
return x;
}
Yes! But you have to find a way to extend the lifetime. One way to do that is to provide mutable reference to a dummy/default value (&mut T) to the function and then fill/replace the value in the function and then return a reference to that value (&T). This way you can specify the lifetime so that the returned reference get the lifetime of a value outside the function.
Examples:
//&mut T -> &T
fn example2<'a>(life: &'a mut Vec<i32>) -> &'a Vec<i32> {
*life = vec![1, 2, 3, 4];
life
}
fn test_example2() {
//Could also use Vec::new()
let mut life = Vec::default();
let res = example2(&mut life);
println!("{:?}", res)
}
fn test2_example2() {
let life = &mut Vec::default();
let res = example2(life);
println!("{:?}", res)
}
//shows real use case
fn get_check_test_slices2<'a>(
lifetime: &'a mut Vec<usize>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
// create a list of primes using a simple primes sieve
*lifetime = primes1_iter_bitvec(limit).collect::<Vec<_>>();
// iterate through pairs of sub slices without copying the primes vec
// slices will be used to check that a complicated sieve is correct
all_test_check_slices(lifetime)
}
Edit:
How is that different from just giving &mut T to the function? (asked by Chayim Friedman (see old solution below)):
It's basically the same... I lost against the borrow checker previously, and that is why I didn't just use &mut T. But after renewed battles I have finally managed to just use &mut T. Thank you for the insightful question.
Old solution:
My solution works by creating a default value before calling the function, which the function later replaces/fills and returns a reference to.
/// Used to return references to values created in a function.
/// fn example<'a>(lt:& 'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
/// lt.set(vec![1,2,3,4]);
/// lt.get()
/// }
pub struct LifeExtender<T> {
value: T,
}
impl<T> Default for LifeExtender<T>
where
T: Default,
{
/// using T default.
fn default() -> Self {
Self {
value: T::default(),
}
}
}
impl<T> LifeExtender<T> {
/// If T doesn't have default.
pub fn new(value: T) -> Self {
Self { value }
}
/// set value to be returned by reference
pub fn set(&mut self, new_value: T) {
self.value = new_value;
}
/// Get a reference with lifetime self.
pub fn get<'a>(&'a self) -> &'a T {
&self.value
}
/// Get a mut reference with lifetime self.
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.value
}
}
fn example<'a>(life: &'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
let local_value = vec![1, 2, 3, 4];
life.set(local_value);
life.get()
}
//prints: [1,2,3,4]
pub fn test_example() {
let mut life = LifeExtender::default();
let res = example(&mut life);
println!("{:?}", res);
}
//Real example code snippet, where I used this solution:
fn get_check_slices2<'a>(
lifetime: &'a mut LifeExtender<Vec<usize>>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
lifetime.set(primes1_iter_bitvec(limit).collect::<Vec<_>>());
all_test_check_slices(lifetime.get())
}

Extracting a mutable reference from an Option

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

Specify lifetime of a returned reference to a closure [duplicate]

I want to write a program that will write a file in 2 steps.
It is likely that the file may not exist before the program is run. The filename is fixed.
The problem is that OpenOptions.new().write() can fail. In that case, I want to call a custom function trycreate(). The idea is to create the file instead of opening it and return a handle. Since the filename is fixed, trycreate() has no arguments and I cannot set a lifetime of the returned value.
How can I resolve this problem?
use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
fn trycreate() -> &OpenOptions {
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("ERR"),
};
f
}
fn main() {
{
let f = OpenOptions::new().write(true).open(b"foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => trycreate("foo.txt"),
};
let buf = b"test1\n";
let _ret = f.write(buf).unwrap();
}
println!("50%");
{
let f = OpenOptions::new().append(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("append"),
};
let buf = b"test2\n";
let _ret = f.write(buf).unwrap();
}
println!("Ok");
}
The question you asked
TL;DR: No, you cannot return a reference to a variable that is owned by a function. This applies if you created the variable or if you took ownership of the variable as a function argument.
Solutions
Instead of trying to return a reference, return an owned object. String instead of &str, Vec<T> instead of &[T], T instead of &T, etc.
If you took ownership of the variable via an argument, try taking a (mutable) reference instead and then returning a reference of the same lifetime.
In rare cases, you can use unsafe code to return the owned value and a reference to it. This has a number of delicate requirements you must uphold to ensure you don't cause undefined behavior or memory unsafety.
See also:
Proper way to return a new string in Rust
Return local String as a slice (&str)
Why can't I store a value and a reference to that value in the same struct?
Deeper answer
fjh is absolutely correct, but I want to comment a bit more deeply and touch on some of the other errors with your code.
Let's start with a smaller example of returning a reference and look at the errors:
fn try_create<'a>() -> &'a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<'a>() -> &'a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Is there any way to return a reference from a function without arguments?
Technically "yes", but for what you want, "no".
A reference points to an existing piece of memory. In a function with no arguments, the only things that could be referenced are global constants (which have the lifetime &'static) and local variables. I'll ignore globals for now.
In a language like C or C++, you could actually take a reference to a local variable and return it. However, as soon as the function returns, there's no guarantee that the memory that you are referencing continues to be what you thought it was. It might stay what you expect for a while, but eventually the memory will get reused for something else. As soon as your code looks at the memory and tries to interpret a username as the amount of money left in the user's bank account, problems will arise!
This is what Rust's lifetimes prevent - you aren't allowed to use a reference beyond how long the referred-to value is valid at its current memory location.
See also:
Is it possible to return either a borrowed or owned type in Rust?
Why can I return a reference to a local literal but not a variable?
Your actual problem
Look at the documentation for OpenOptions::open:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
It returns a Result<File>, so I don't know how you'd expect to return an OpenOptions or a reference to one. Your function would work if you rewrote it as:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn't open")
}
This uses Result::expect to panic with a useful error message. Of course, panicking in the guts of your program isn't super useful, so it's recommended to propagate your errors back out:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option and Result have lots of nice methods to deal with chained error logic. Here, you can use or_else:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
I'd also return the Result from main. All together, including fjh's suggestions:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1\n")?;
f.write_all(b"test2\n")?;
Ok(())
}
Is there any way to return a reference from a function without arguments?
No (except references to static values, but those aren't helpful here).
However, you might want to look at OpenOptions::create. If you change your first line in main to
let f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
the file will be created if it does not yet exist, which should solve your original problem.
You can not return a reference pointing to a local variable. You have two alternatives, either return the value or use a static variable.
Here is why:
References are pointers to memory locations. Once functions are executed, local variables are popped off the execution stack and resources are de-allocated. After that point, any reference to a local variable will be pointing to some useless data. Since it is de-allocated, it is not in our program's possession any more and OS may have already given it to another process and our data may have been overwritten.
For the following example, x is created when the function runs and dropped off when the function completes executing. It is local to the function and lives on this particular function's stack. Function's stack holds local variables.
When run is pop off the execution stack, any reference to x, &x, will be pointing to some garbage data. That is what people call a dangling pointer. The Rust compiler does not allow to use dangling pointers since it is not safe.
fn run() -> &u32 {
let x: u32 = 42;
return &x;
} // x is dropped here
fn main() {
let x = run();
}
So, that is why we can not return a reference to a local variable. We have two options: either return the value or use a static variable.
Returning the value is the best option here. By returning the value, you will be passing the result of your calculation to the caller, in Rust's terms x will be owned by the caller. In our case it is main. So, no problem there.
Since a static variable lives as long as the process runs, its references will be pointing to the same memory location both inside and outside the function. No problem there either.
Note: #navigaid advises using a box, but it does not make sense because you are moving readily available data to heap by boxing it and then returning it. It does not solve the problem, you are still returning the local variable to the caller but using a pointer when accessing it. It adds an unnecessary indirection due to de-referencing hence incurring additional cost. Basically you will be using & for the sake of using it, nothing more.
This is an elaboration on snnsnn's answer, which briefly explained the problem without being too specific.
Rust doesn't allow return a reference to a variable created in a function. Is there a workaround? Yes, simply put that variable in a Box then return it. Example:
fn run() -> Box<u32> {
let x: u32 = 42;
return Box::new(x);
}
fn main() {
println!("{}", run());
}
code in rust playground
As a rule of thumb, to avoid similar problems in Rust, return an owned object (Box, Vec, String, ...) instead of reference to a variable:
Box<T> instead of &T
Vec<T> instead of &[T]
String instead of &str
For other types, refer to The Periodic Table of Rust Types to figure out which owned object to use.
Of course, in this example you can simply return the value (T instead of &T or Box<T>)
fn run() -> u32 {
let x: u32 = 42;
return x;
}
Yes! But you have to find a way to extend the lifetime. One way to do that is to provide mutable reference to a dummy/default value (&mut T) to the function and then fill/replace the value in the function and then return a reference to that value (&T). This way you can specify the lifetime so that the returned reference get the lifetime of a value outside the function.
Examples:
//&mut T -> &T
fn example2<'a>(life: &'a mut Vec<i32>) -> &'a Vec<i32> {
*life = vec![1, 2, 3, 4];
life
}
fn test_example2() {
//Could also use Vec::new()
let mut life = Vec::default();
let res = example2(&mut life);
println!("{:?}", res)
}
fn test2_example2() {
let life = &mut Vec::default();
let res = example2(life);
println!("{:?}", res)
}
//shows real use case
fn get_check_test_slices2<'a>(
lifetime: &'a mut Vec<usize>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
// create a list of primes using a simple primes sieve
*lifetime = primes1_iter_bitvec(limit).collect::<Vec<_>>();
// iterate through pairs of sub slices without copying the primes vec
// slices will be used to check that a complicated sieve is correct
all_test_check_slices(lifetime)
}
Edit:
How is that different from just giving &mut T to the function? (asked by Chayim Friedman (see old solution below)):
It's basically the same... I lost against the borrow checker previously, and that is why I didn't just use &mut T. But after renewed battles I have finally managed to just use &mut T. Thank you for the insightful question.
Old solution:
My solution works by creating a default value before calling the function, which the function later replaces/fills and returns a reference to.
/// Used to return references to values created in a function.
/// fn example<'a>(lt:& 'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
/// lt.set(vec![1,2,3,4]);
/// lt.get()
/// }
pub struct LifeExtender<T> {
value: T,
}
impl<T> Default for LifeExtender<T>
where
T: Default,
{
/// using T default.
fn default() -> Self {
Self {
value: T::default(),
}
}
}
impl<T> LifeExtender<T> {
/// If T doesn't have default.
pub fn new(value: T) -> Self {
Self { value }
}
/// set value to be returned by reference
pub fn set(&mut self, new_value: T) {
self.value = new_value;
}
/// Get a reference with lifetime self.
pub fn get<'a>(&'a self) -> &'a T {
&self.value
}
/// Get a mut reference with lifetime self.
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.value
}
}
fn example<'a>(life: &'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
let local_value = vec![1, 2, 3, 4];
life.set(local_value);
life.get()
}
//prints: [1,2,3,4]
pub fn test_example() {
let mut life = LifeExtender::default();
let res = example(&mut life);
println!("{:?}", res);
}
//Real example code snippet, where I used this solution:
fn get_check_slices2<'a>(
lifetime: &'a mut LifeExtender<Vec<usize>>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
lifetime.set(primes1_iter_bitvec(limit).collect::<Vec<_>>());
all_test_check_slices(lifetime.get())
}

Why would a function taking no arguments and returning a reference have a lifetime error? [duplicate]

I want to write a program that will write a file in 2 steps.
It is likely that the file may not exist before the program is run. The filename is fixed.
The problem is that OpenOptions.new().write() can fail. In that case, I want to call a custom function trycreate(). The idea is to create the file instead of opening it and return a handle. Since the filename is fixed, trycreate() has no arguments and I cannot set a lifetime of the returned value.
How can I resolve this problem?
use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
fn trycreate() -> &OpenOptions {
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("ERR"),
};
f
}
fn main() {
{
let f = OpenOptions::new().write(true).open(b"foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => trycreate("foo.txt"),
};
let buf = b"test1\n";
let _ret = f.write(buf).unwrap();
}
println!("50%");
{
let f = OpenOptions::new().append(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("append"),
};
let buf = b"test2\n";
let _ret = f.write(buf).unwrap();
}
println!("Ok");
}
The question you asked
TL;DR: No, you cannot return a reference to a variable that is owned by a function. This applies if you created the variable or if you took ownership of the variable as a function argument.
Solutions
Instead of trying to return a reference, return an owned object. String instead of &str, Vec<T> instead of &[T], T instead of &T, etc.
If you took ownership of the variable via an argument, try taking a (mutable) reference instead and then returning a reference of the same lifetime.
In rare cases, you can use unsafe code to return the owned value and a reference to it. This has a number of delicate requirements you must uphold to ensure you don't cause undefined behavior or memory unsafety.
See also:
Proper way to return a new string in Rust
Return local String as a slice (&str)
Why can't I store a value and a reference to that value in the same struct?
Deeper answer
fjh is absolutely correct, but I want to comment a bit more deeply and touch on some of the other errors with your code.
Let's start with a smaller example of returning a reference and look at the errors:
fn try_create<'a>() -> &'a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<'a>() -> &'a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Is there any way to return a reference from a function without arguments?
Technically "yes", but for what you want, "no".
A reference points to an existing piece of memory. In a function with no arguments, the only things that could be referenced are global constants (which have the lifetime &'static) and local variables. I'll ignore globals for now.
In a language like C or C++, you could actually take a reference to a local variable and return it. However, as soon as the function returns, there's no guarantee that the memory that you are referencing continues to be what you thought it was. It might stay what you expect for a while, but eventually the memory will get reused for something else. As soon as your code looks at the memory and tries to interpret a username as the amount of money left in the user's bank account, problems will arise!
This is what Rust's lifetimes prevent - you aren't allowed to use a reference beyond how long the referred-to value is valid at its current memory location.
See also:
Is it possible to return either a borrowed or owned type in Rust?
Why can I return a reference to a local literal but not a variable?
Your actual problem
Look at the documentation for OpenOptions::open:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
It returns a Result<File>, so I don't know how you'd expect to return an OpenOptions or a reference to one. Your function would work if you rewrote it as:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn't open")
}
This uses Result::expect to panic with a useful error message. Of course, panicking in the guts of your program isn't super useful, so it's recommended to propagate your errors back out:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option and Result have lots of nice methods to deal with chained error logic. Here, you can use or_else:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
I'd also return the Result from main. All together, including fjh's suggestions:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1\n")?;
f.write_all(b"test2\n")?;
Ok(())
}
Is there any way to return a reference from a function without arguments?
No (except references to static values, but those aren't helpful here).
However, you might want to look at OpenOptions::create. If you change your first line in main to
let f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
the file will be created if it does not yet exist, which should solve your original problem.
You can not return a reference pointing to a local variable. You have two alternatives, either return the value or use a static variable.
Here is why:
References are pointers to memory locations. Once functions are executed, local variables are popped off the execution stack and resources are de-allocated. After that point, any reference to a local variable will be pointing to some useless data. Since it is de-allocated, it is not in our program's possession any more and OS may have already given it to another process and our data may have been overwritten.
For the following example, x is created when the function runs and dropped off when the function completes executing. It is local to the function and lives on this particular function's stack. Function's stack holds local variables.
When run is pop off the execution stack, any reference to x, &x, will be pointing to some garbage data. That is what people call a dangling pointer. The Rust compiler does not allow to use dangling pointers since it is not safe.
fn run() -> &u32 {
let x: u32 = 42;
return &x;
} // x is dropped here
fn main() {
let x = run();
}
So, that is why we can not return a reference to a local variable. We have two options: either return the value or use a static variable.
Returning the value is the best option here. By returning the value, you will be passing the result of your calculation to the caller, in Rust's terms x will be owned by the caller. In our case it is main. So, no problem there.
Since a static variable lives as long as the process runs, its references will be pointing to the same memory location both inside and outside the function. No problem there either.
Note: #navigaid advises using a box, but it does not make sense because you are moving readily available data to heap by boxing it and then returning it. It does not solve the problem, you are still returning the local variable to the caller but using a pointer when accessing it. It adds an unnecessary indirection due to de-referencing hence incurring additional cost. Basically you will be using & for the sake of using it, nothing more.
This is an elaboration on snnsnn's answer, which briefly explained the problem without being too specific.
Rust doesn't allow return a reference to a variable created in a function. Is there a workaround? Yes, simply put that variable in a Box then return it. Example:
fn run() -> Box<u32> {
let x: u32 = 42;
return Box::new(x);
}
fn main() {
println!("{}", run());
}
code in rust playground
As a rule of thumb, to avoid similar problems in Rust, return an owned object (Box, Vec, String, ...) instead of reference to a variable:
Box<T> instead of &T
Vec<T> instead of &[T]
String instead of &str
For other types, refer to The Periodic Table of Rust Types to figure out which owned object to use.
Of course, in this example you can simply return the value (T instead of &T or Box<T>)
fn run() -> u32 {
let x: u32 = 42;
return x;
}
Yes! But you have to find a way to extend the lifetime. One way to do that is to provide mutable reference to a dummy/default value (&mut T) to the function and then fill/replace the value in the function and then return a reference to that value (&T). This way you can specify the lifetime so that the returned reference get the lifetime of a value outside the function.
Examples:
//&mut T -> &T
fn example2<'a>(life: &'a mut Vec<i32>) -> &'a Vec<i32> {
*life = vec![1, 2, 3, 4];
life
}
fn test_example2() {
//Could also use Vec::new()
let mut life = Vec::default();
let res = example2(&mut life);
println!("{:?}", res)
}
fn test2_example2() {
let life = &mut Vec::default();
let res = example2(life);
println!("{:?}", res)
}
//shows real use case
fn get_check_test_slices2<'a>(
lifetime: &'a mut Vec<usize>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
// create a list of primes using a simple primes sieve
*lifetime = primes1_iter_bitvec(limit).collect::<Vec<_>>();
// iterate through pairs of sub slices without copying the primes vec
// slices will be used to check that a complicated sieve is correct
all_test_check_slices(lifetime)
}
Edit:
How is that different from just giving &mut T to the function? (asked by Chayim Friedman (see old solution below)):
It's basically the same... I lost against the borrow checker previously, and that is why I didn't just use &mut T. But after renewed battles I have finally managed to just use &mut T. Thank you for the insightful question.
Old solution:
My solution works by creating a default value before calling the function, which the function later replaces/fills and returns a reference to.
/// Used to return references to values created in a function.
/// fn example<'a>(lt:& 'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
/// lt.set(vec![1,2,3,4]);
/// lt.get()
/// }
pub struct LifeExtender<T> {
value: T,
}
impl<T> Default for LifeExtender<T>
where
T: Default,
{
/// using T default.
fn default() -> Self {
Self {
value: T::default(),
}
}
}
impl<T> LifeExtender<T> {
/// If T doesn't have default.
pub fn new(value: T) -> Self {
Self { value }
}
/// set value to be returned by reference
pub fn set(&mut self, new_value: T) {
self.value = new_value;
}
/// Get a reference with lifetime self.
pub fn get<'a>(&'a self) -> &'a T {
&self.value
}
/// Get a mut reference with lifetime self.
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.value
}
}
fn example<'a>(life: &'a mut LifeExtender<Vec<i32>>) -> &'a Vec<i32> {
let local_value = vec![1, 2, 3, 4];
life.set(local_value);
life.get()
}
//prints: [1,2,3,4]
pub fn test_example() {
let mut life = LifeExtender::default();
let res = example(&mut life);
println!("{:?}", res);
}
//Real example code snippet, where I used this solution:
fn get_check_slices2<'a>(
lifetime: &'a mut LifeExtender<Vec<usize>>,
limit: usize,
) -> impl Iterator<Item = (&'a [usize], &'a [usize])> + 'a {
lifetime.set(primes1_iter_bitvec(limit).collect::<Vec<_>>());
all_test_check_slices(lifetime.get())
}

Resources