Reference has shorter lifetime than its value from same scope? - loops

It appears in my code that a value is living longer than a reference to it, even though both are created in the same scope. I'd like to know why, and how I can adjust the lifetime of my reference.
Example 1 is accepted by the compiler...
let mut rxs: Vec<Receiver<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
let (tx, rx) = sync_channel(0);
txs.push(tx);
rxs.push(rx);
}
But Example 2 isn't...
let sel = Select::new();
let mut handles: Vec<Handle<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
let (tx, rx) = sync_channel(0);
txs.push(tx);
handles.push(sel.handle(&rx));
}
The compiler tells me that the reference &rx is borrowed in the last line of the for loop, but is dropped at the end of the for loop and needs to live longer, presumably because the reference is placed in a structure with longer lifetime. Why would the reference have a different lifetime than the value, and if the value can be moved into a structure as in the first example, why not a reference like in the second?
Finally, I'd like to know why I don't encounter the same issue in Example 3, even though a reference is borrowed and passed into a structure that lasts longer than the scope of the borrow...
let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
(0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
rxs.iter().map(|x| sel.handle(&x)).collect();

In the first example you are moving rx into the rxs vec. That's fine because you move the ownership of rx too, and it won't get dropped.
In the second example, you are passing a reference to sel.handle(), which is another way of saying it is being borrowed. rx is dropped at the end of each loop iteration, but handles outlives the entire loop. If the compiler didn't stop this from happening then handles would be full of dangling pointers.
But why would the reference have a different lifetime than the value
A reference always has a shorter lifetime than the value that it references. This has to be the case: the reference must exist and be allocated to memory before you can find its address. After a value is dropped, any reference to it is pointing at freed memory, which could be being used for something else.
and if the value can be moved into a structure as in the first example, why not a reference like in the second?
In the second example, the reference is being moved. But the original value isn't. The reference is now pointing at the free memory which was previously used by rx.
In the third example, you have created vectors which own all of the Senders and Receivers. As long as txs and rxs stay in scope, these values will not be dropped.

In example 2, rx does not have the same lifetime as handles. In fact, it's dropped at the end of the loop, like this:
let sel = Select::new();
let mut handles: Vec<Handle<String>> = Vec::new();
let mut txs: Vec<SyncSender<String>> = Vec::new();
for _ in 0..N {
let (tx, rx) = sync_channel(0);
txs.push(tx);
handles.push(sel.handle(&rx));
drop(tx);
drop(rx);
}
drop(txs);
drop(handles);
drop(sel);
Exmaple 3 is not equivalent to example 2. This is equivalent to example 2, and it fails:
let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
(0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
rxs.into_iter().map(|x| sel.handle(&x)).collect(); // <-- notice: into_iter()
The iter() function returns an iterator of references. That's why this works:
let (txs, rxs): (Vec<SyncSender<String>>, Vec<Receiver<String>>) =
(0..N).map(|_| sync_channel(0)).unzip();
let handles: Vec<Handle<String>> =
rxs.iter().map(|x| sel.handle(x)).collect(); // <-- notice: no `&`

Related

How to modify a Cow variable that uses itself in a loop?

I am trying to remove all the parentheses in a string. Not thinking about it too hard, I just do a simple regexp replace (i.e. the problem in question is not particularly about getting rid of arbitrary levels of nested parentheses, but feel free to suggest a better way of doing that in a comment if you want).
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = "Text (with some (nested) parentheses)!";
let re = Regex::new(r"\([^()]*\)")?;
let output = re.replace_all(&input, "");
let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// let output = re.replace_all(&output, "");
// ...
assert_eq!("Text !", output);
println!("Works!");
Ok(())
}
Because I do not know how nested the parentheses will be, I need to do the replacement in a loop rather than repeating it "just enough times". Creating a loop, however, creates a new scope and that's where I'm hitting a dead point in the discussion with the borrow checker.
The simplest case that shows what I am trying to do in the loop would be:
let mut output = re.replace_all(&input, "");
while re.is_match(&output) {
output = re.replace_all(&output, "");
}
However that cannot be done because I am assigning to a borrowed variable:
error[E0506]: cannot assign to `output` because it is borrowed
--> src/main.rs:9:9
|
9 | output = re.replace_all(&output, "");
| ^^^^^^ ------- borrow of `output` occurs here
| |
| assignment to borrowed `output` occurs here
| borrow later used here
What I would like to do, ideally, is to create new variable binding with the same name, but using let output = will shadow the outer variable binding, so the loop would cycle infinitely.
No matter what inner or outer temporary variable I create I cannot make it do what I want. I also tried using the fact that re.replace_all() returns Cow and tried using .to_owned() and .to_string() in a couple of places, but that didn't help either.
Here's a link to a playground.
re.replace_all() returns Cow
This is the root of the problem. The compiler knows that the return value might reference output, but it will also replace output, causing output to be dropped right away. If it allowed this, the reference would point to unallocated memory, leading to memory unsafety.
The solution is to avoid borrowing at all.
tried using .to_owned()
to_owned on a Cow just returns the same Cow. Perhaps you meant into_owned?
let mut output = re.replace_all(&input, "").into_owned();
while re.is_match(&output) {
output = re.replace_all(&output, "").into_owned();
}
and .to_string() in a couple of places
This works as well:
let mut output = re.replace_all(&input, "").to_string();
while re.is_match(&output) {
output = re.replace_all(&output, "").to_string();
}
Shepmaster's answer works, but it's not as efficient as it could be. A subtle property of the Cow type is that by inspecting it, we can determine whether the string was modified, and skip work if it wasn't.
Due to constraints of the Rust type system, if the value was not modified then Cow::into_owned() makes a copy. (Cow::into_owned() of a modified value does not copy). (into_owned documentation)
In your use case, we can detect unmodified Cow -- Cow::Borrowed -- and skip into_owned().
let mut output = /* mutable String */;
while re.is_match(&output).unwrap() {
match re.replace_all(&output, "") {
// Unmodified -- skip copy
Cow::Borrowed(_) => {}
// replace_all() returned a new value that we already own
Cow::Owned(new) => output = new,
}
}
But we can go further. Calling both is_match() and replace_all() means the pattern is matched twice. With our new knowledge of Cows, we can optimize that away:
let mut output = /* mutable String */;
// Cow::Owned is returned when the string was modified.
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = new;
}
Edit: If your input value is immutable, you can avoid the .to_string() copy by making it Cow as well:
let input = "value";
let mut output = Cow::from(input);
while let Cow::Owned(new) = re.replace_all(&output, "") {
output = Cow::Owned(new);
}

Getting "temporary value dropped while borrowed" when trying to update an Option<&str> in a loop

I'm trying to implement a commonly used pattern - using the result of a previous loop iteration in the next loop iteration. For example, to implement pagination where you need to give the id of the last value on the previous page.
struct Result {
str: String,
}
fn main() {
let times = 10;
let mut last: Option<&str> = None;
for i in 0..times {
let current = do_something(last);
last = match current {
Some(r) => Some(&r.str.to_owned()),
None => None,
};
}
}
fn do_something(o: Option<&str>) -> Option<Result> {
Some(Result {
str: "whatever string".to_string(),
})
}
However, I'm not sure how to actually get the value out of the loop. Currently, the compiler error is temporary value dropped while borrowed (at &r.str.to_owned()), though I made many other attempts, but to no avail.
The only way I found to actually get it working is to create some sort of local tmp_str variable and do a hack like this:
match current {
Some(r) => {
tmp_str.clone_from(&r.str);
last = Some(&tmp_str);
}
None => {
last = None;
}
}
But that doesn't feel like it's the way it's supposed to be done.
In your code, it remains unclear who the owner of the String referenced in last: Option<&str> is supposed to be. You could introduce an extra mutable local variable that owns the string. But then you would have two variables: the owner and the reference, which seems redundant. It would be much simpler to just make last the owner:
struct MyRes {
str: String,
}
fn main() {
let times = 10;
let mut last: Option<String> = None;
for _i in 0..times {
last = do_something(&last).map(|r| r.str);
}
}
fn do_something(_o: &Option<String>) -> Option<MyRes> {
Some(MyRes {
str: "whatever string".to_string(),
})
}
In do_something, you can just pass the whole argument by reference, this seems more likely to be what you wanted. Also note that naming your own struct Result is a bad idea, because Result is such a pervasive trait built deeply into the compiler (?-operator etc).
Follow-up question: Option<&str> or Option<String>?
Both Option<&str> and Option<String> have different trade-offs. One is better for passing string literals, other is better for passing owned Strings. I'd actually propose to use neither, and instead make the function generic over type S that implements AsRef<str>. Here is a comparison of various methods:
fn do_something(o: &Option<String>) {
let _a: Option<&str> = o.as_ref().map(|r| &**r);
let _b: Option<String> = o.clone();
}
fn do_something2(o: &Option<&str>) {
let _a: Option<&str> = o.clone(); // do you need it?
let _b: Option<String> = o.map(|r| r.to_string());
}
fn do_something3<S: AsRef<str>>(o: &Option<S>) {
let _a: Option<&str> = o.as_ref().map(|s| s.as_ref());
let _b: Option<String> = o.as_ref().map(|r| r.as_ref().to_string());
}
fn main() {
let x: Option<String> = None;
let y: Option<&str> = None;
do_something(&x); // nice
do_something(&y.map(|r| r.to_string())); // awkward & expensive
do_something2(&x.as_ref().map(|x| &**x)); // cheap but awkward
do_something2(&y); // nice
do_something3(&x); // nice
do_something3(&y); // nice, in both cases
}
Note that not all of the above combinations are very idiomatic, some are added just for completeness (e.g. asking for AsRef<str> and then building an owned String out of seems a bit strange).
r.str.to_owned() is a temporary value. You can take a reference to a temporary, but because the temporary value will usually be dropped (destroyed) at the end of the innermost enclosing statement, the reference becomes dangling at that point. In this case the "innermost enclosing statement" is either the last line of the loop, or the loop body itself -- I'm not sure exactly which one applies here, but it doesn't matter, because either way, you're trying to make last contain a reference to a String that will soon be dropped, making last unusable. The compiler is right to stop you from using it again in the next iteration of the loop.
The easiest fix is just to not make last a reference at all -- in the example, it's not necessary or desirable. Just use Option<String>:
fn main() {
let times = 10;
let mut last = None;
for _ in 0..times {
last = match do_something(last) {
Some(r) => Some(r.str),
None => None,
};
}
}
fn do_something(_: Option<String>) -> Option<Result> {
// ...
}
There are also ways to make the reference version work; here is one:
let mut current; // lift this declaration out of the loop so `current` will have
// a lifetime longer than one iteration
for _ in 0..times {
current = do_something(last);
last = match current {
Some(ref r) => Some(&r.str), // borrow from `current` in the loop instead
// of from a newly created String
None => None,
};
}
You might want to do this if your code is more complicated than the example and using String would mean a lot of potentially expensive .clone()s.

Why does a File need to be mutable to call Read::read_to_string?

Here's a line from the 2nd edition Rust tutorial:
let mut f = File::open(filename).expect("file not found");
I'm of the assumption that the file descriptor is a wrapper around a number that basically doesn't change and is read-only.
The compiler complains that the file cannot be borrowed mutably, and I'm assuming it's because the method read_to_string takes the instance as the self argument as mutable, but the question is "why"? What is ever going to change about the file descriptor? Is it keeping track of the cursor location or something?
error[E0596]: cannot borrow immutable local variable `fdesc` as mutable
--> main.rs:13:5
|
11 | let fdesc = File::open(fname).expect("file not found");
| ----- consider changing this to `mut fdesc`
12 | let mut fdata = String::new();
13 | fdesc.read_to_string(&mut fdata)
| ^^^^^ cannot borrow mutably
The whole source:
fn main() {
let args: Vec<String> = env::args().collect();
let query = &args[1];
let fname = &args[2];
println!("Searching for '{}' in file '{}'...", query, fname);
let fdesc = File::open(fname).expect("file not found"); //not mut
let mut fdata = String::new();
fdesc.read_to_string(&mut fdata)
.expect("something went wrong reading the file");
println!("Found: \n{}", fdata);
}
I'm assuming it's because the method read_to_string takes the instance as the self argument as mutable
Yes, that's correct:
fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
The trait method Read::read_to_string takes the receiver as a mutable reference because in general, that's what is needed to implement "reading" from something. You are going to change a buffer or an offset or something.
Yes, an actual File may simply contain an underlying file descriptor (e.g. on Linux or macOS) or a handle (e.g. Windows). In these cases, the operating system deals with synchronizing the access across threads. That's not even guaranteed though — it depends on the platform. Something like Redox might actually have a mutable reference in its implementation of File.
If the Read trait didn't accept a &mut self, then types like BufReader would have to use things like internal mutability, reducing the usefulness of Rust's references.
See also:
Why is it possible to implement Read on an immutable reference to File?

How do I move String values from an array to a tuple without copying?

I have a fixed size array of Strings: [String; 2]. I want to turn it into a (String, String). Can I do this without copying the values?
The piece of code that I'm working on in particular is the following:
let (basis, names_0, names_1) = if let Some(names) = self.arg_name {
(ComparisonBasis::Name, names[0], names[1])
} else {
(ComparisonBasis::File, self.arg_file[0], self.arg_file[1])
};
types:
self.arg_name: Option<[String; 2]>
self.arg_file: Vec<String>
Right now I'm getting errors
cannot move out of type `[std::string::String; 2]`, a non-copy fixed-size array [E0508]
and
cannot move out of indexed content [E0507]
for the two arms of the if
You've omitted a fair amount of context, so I'm taking a guess at a few aspects. I'm also hewing a little closer to the question you asked, rather than the vaguer one implied by your snippets.
struct NeverSpecified {
arg_names: Option<[String; 2]>,
arg_file: Vec<String>,
}
impl NeverSpecified {
fn some_method_i_guess(mut self) -> (String, String) {
if let Some(mut names) = self.arg_names {
use std::mem::replace;
let name_0 = replace(&mut names[0], String::new());
let name_1 = replace(&mut names[1], String::new());
(name_0, name_1)
} else {
let mut names = self.arg_file.drain(0..2);
let name_0 = names.next().expect("expected 2 names, got 0");
let name_1 = names.next().expect("expected 2 names, got 1");
(name_0, name_1)
}
}
}
I use std::mem::replace to switch the contents of the array, whilst leaving it in a valid state. This is necessary because Rust won't allow you to have a "partially valid" array. There are no copies or allocations involved in this path.
In the other path, we have to pull elements out of the vector by hand. Again, you can't just move values out of a container via indexing (this is actually a limitation of indexing overall). Instead, I use Vec::drain to essentially chop the first two elements out of the vector, then extract them from the resulting iterator. To be clear: this path doesn't involve any copies or allocations, either.
As an aside, those expect methods shouldn't ever be triggered (since drain does bounds checking), but better paranoid than sorry; if you want to replace them with unwrap() calls instead, that should be fine..
Since Rust 1.36, you can use slice patterns to bind to all the values of the array at once:
struct NeverSpecified {
arg_names: Option<[String; 2]>,
arg_file: Vec<String>,
}
impl NeverSpecified {
fn some_method_i_guess(mut self) -> (String, String) {
if let Some([name_0, name_1]) = self.arg_names.take() {
(name_0, name_1)
} else {
let mut names = self.arg_file.drain(0..2);
let name_0 = names.next().expect("expected 2 names, got 0");
let name_1 = names.next().expect("expected 2 names, got 1");
(name_0, name_1)
}
}
}
See also:
Method for safely moving all elements out of a generic array into a tuple with minimal overhead

Having array problems in Swift

I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.

Resources