I want to mutate some data in the pad.
I see an example of working with pads here https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/blob/0.18.8/examples/src/bin/pad_probes.rs#L40
It seems like I can only use callbacks that don't modify anything they capture since the callback type is func: F . I tried to simply use one of my variables inside the closure and got this:
error[E0594]: cannot assign to `self.frame_id`, as `Fn` closures cannot mutate their captured variables
--> src/decoding_branch.rs:161:13
|
161 | self.frame_id += 1;
| ^^^^^^^^^^^^^^^^^^ cannot assign
How I'm supposed to change anything in pads?
My bad. I should use something like Cannot borrow captured outer variable in an `Fn` closure as mutable
I tried the following to check this approach
let frame_id = Arc::new(Mutex::new(0));
nvv4l2dec_src.add_probe(gst::PadProbeType::BUFFER, move |_, probe_info| {
let mut frame_id = frame_id.lock().unwrap();
*frame_id += 1;
println!("{:?}", frame_id);
});
and it seems like it works.
Related
Let's say I'm using a nested closure to modify a local variable like so:
let mut i = 0;
let x = (0..).flat_map(|_| {
(0..).map(|_| {
let x = i;
i += 1;
x
})
});
This does not compile with the error:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:35:9
|
32 | let mut i = 0;
| ----- variable defined here
33 |
34 | let x = (0..).flat_map(|_| {
| - inferred to be a `FnMut` closure
35 | / (0..).map(|_| {
36 | | let x = i;
| | - variable captured here
37 | | i += 1;
38 | | x
39 | | })
| |__________^ returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
I experimented with the same code on a non-nested context, and it compiles without an error:
let mut i = 0;
let x = (0..).map(|_| {
let x = i;
i += 1;
x
});
So I guess the error comes from the fact that the closure is nested, but I can't fully figure out why the error is being triggered.
Let's strip out all of the iterator parts and consider just the closures that are being constructed.
let mut i = 0;
let f = || {
|| {
let x = i;
i += 1;
x
}
};
i is a variable being used by the inner closure, and therefore borrowed by it. Now, think about what happens if I run this program:
let c1 = f();
let c2 = f();
[c1(), c2()]
Both c1 and c2 are closures that capture i and mutate it. Therefore, having both of them allows shared mutable state without any synchronization/mutual-exclusion mechanism, which is always prohibited in Rust. Compiling the above code will produce the same error as you had.
Iterator::flat_map() won't actually call the function and keep two of it around like this, but its signature can't communicate that fact to the compiler, so the compiler has to assume the worst could happen.
Now that we know that it would be unsound to permit this pattern, why is the error described the way you saw?
When you refer to a variable in a closure, this (most often) becomes a borrow of that variable. In other words, calling || { i += 1; } constructs a value that contains an &mut i32 pointing to i. This means that || { i += 1; } itself is an expression that needs to be able to mutably borrow i, so a closure which contains || { i += 1; } itself requires a mutable borrow of i.
Whenever a closure contains a mutable borrow (or some other cases), that means that invoking the closure itself requires &mut self (on the same general principle that you can't ever mutate an &mut by way of an &). That's why the closures are inferred to be FnMuts (the type of function that requires &mut self to invoke) and the compiler is telling you about that.
Now, why do FnMut closures “only have access to their captured variables while they are executing”? I'm not sure how to explain this exact description of the problem, but I'm sure that it's fundamentally about the requirement of &mut being unique, and that if it were permitted there would end up being some way to modify the function's state while its result was still borrowed.
Finally, how do you solve your problem? Well, in simple cases, the answer is usually to make the closure a move || { closure. That means there is no longer a borrow, and the closure now owns the i counter, so it can live as long as the closure does. But in your case, this doesn't help, because you're actually trying (I assume) to have a counter which is shared between everything. Therefore you need an interior mutability tool. The simplest one for this situation is Cell, which allows reading and writing a value (as long as it's Copy) without ever borrowing it.
use std::cell::Cell;
let i = Cell::new(0);
let x = (0..).flat_map(|_| {
(0..).map(|_| {
let x: i32 = i.get();
i.set(x + 1);
x
})
});
I'm getting
error[E0373]: closure may outlive the current function, but it borrows row_nr, which is owned by the current function
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved:
fn get_neighbours(values: &Vec<Vec<u32>>, row: usize, col: usize) -> Vec<u32> {
vec![
values.get(row - 1).and_then(|cols| cols.get(col)),
values.get(row).and_then(|cols| cols.get(col - 1)),
values.get(row).and_then(|cols| cols.get(col + 1)),
values.get(row + 1).and_then(|cols| cols.get(col)),
].into_iter().filter_map(|value_opt| value_opt.map(|value| *value)).collect()
}
fn get_points(values: Vec<Vec<u32>>) -> Vec<(u32, Vec<u32>)> {
values
.iter()
.enumerate()
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map(|(column_nr, height)| {
let neighbours = get_neighbours(&values, row_nr, column_nr);
(*height, neighbours)
})
}).collect()
}
Full error message:
--> src/lib.rs:16:44
|
16 | columns.iter().enumerate().map(|(column_nr, height)| {
| ^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `row_nr`
17 | let neighbours = get_neighbours(&values, row_nr, column_nr);
| ------ `row_nr` is borrowed here
|
note: closure is returned here
--> src/lib.rs:16:13
|
16 | / columns.iter().enumerate().map(|(column_nr, height)| {
17 | | let neighbours = get_neighbours(&values, row_nr, column_nr);
18 | | (*height, neighbours)
19 | | })
| |______________^
help: to force the closure to take ownership of `row_nr` (and any other referenced variables), use the `move` keyword
|
16 | columns.iter().enumerate().map(move |(column_nr, height)| {
| ++++
See also on the Rust playground.
Now, the error suggest using move, but that becomes problematic because I'd only like to pass a reference to the values Vec (which I don't think should outlive the closure, because get_neighbours takes u32s from that Vec and thus should make copies too, I think?).
I presume I'm misunderstanding lifetimes here. I'd appreciate any insights on what I'm misinterpreting. I looked at a couple of related questions, but they seem to either resolve it using a move (which, as mentioned above, I think I should (be able to) avoid?), or have multiple borrow checker issues, making it hard for me to understand which applies ones to me (e.g. this answer).
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved
This expectation is correct, assuming it were moved in the first place. In this case it's not moved, it's borrowed, because by default closures borrow values from their environment. To request a move, which will for u32 indeed result in a copy, you need to use the move keyword explicitly.
As you discovered, when you just use move, you also move values, which doesn't compile and is anyway not what you want. The standard Rust idiom to move only one value into the closure is to use move and explicitly borrow the captured variables you don't want moved (in yout case values). For example, this compiles:
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map({
let values = &values;
move |(column_nr, height)| {
let neighbours = get_neighbours(values, row_nr, column_nr);
(*height, neighbours)
}
})
})
Playground
As for your titular question of why may a closure outlive the current function: Note that the "current function" in the error message refers to the outer closure, the one passed to flat_map(). Since the inner closure becomes part of the iterator returned by map(), and the outer closure immediately returns that iterator, it is trivially true that the inner closure does outlive the "current function" and that it cannot be allowed to borrow either row_nr or columns. (But borrowing values is perfectly fine because values outlives both closures.)
Please help me to compile my code attached bellow. The compiler says that following 2 patterns depending on which lines I comment out.
The program reads a &str which is a simple "svg path command" like code then parses it. The pasted code has been simplified for simplicity. It uses Regex to split the input string into lines then study each line in the main for loop. Each loop pushes the parse result onto a vector. Finally the function returns the vector.
Basically the compiler says returning the vector is not allowed because it refers local variable. Though I don't have any workaround.
error[E0597]: `cmd` does not live long enough
--> src/main.rs:24:25
|
24 | codeV = re.captures(cmd.as_str());
| ----- ^^^ borrowed value does not live long enough
| |
| borrow might be used here, when `codeV` is dropped and runs the destructor for type `Option<regex::Captures<'_>>`
...
30 | }
| - `cmd` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are defined
error[E0515]: cannot return value referencing local variable `cmd`
--> src/main.rs:31:1
|
24 | codeV = re.captures(cmd.as_str());
| --- `cmd` is borrowed here
...
31 | V //Error
| ^ returns a value referencing data owned by the current function
Playground
use regex::Regex;
pub fn parse(path:&str) {//->Vec<Option<regex::Captures<>>> //Error
let reg_n=Regex::new(r"\n").unwrap();
let path=reg_n.replace_all("\n"," ");
let reg_cmd=Regex::new(r"(?P<cmd>[mlhv])").unwrap();
let path=reg_cmd.replace_all(&path,"\n${cmd}");
let cmdV=reg_n.split(&path);
//let cmdV:Vec<&str> = reg.split(path).map(|x|x).collect();
let mut V:Vec<Option<regex::Captures<>>>=vec![];
let mut codeV:Option<regex::Captures<>>=None;
let mut count=0;
for cmd_f in cmdV{//This loop block has been simplified.
count+=1;
if count==1{continue;}
let mut cmd="".to_string();
cmd=cmd_f.to_string();
cmd=cmd.replace(" ","");
let re = Regex::new(r"\{(?P<code>[^\{^\}]{0,})\}").unwrap();
codeV = re.captures(cmd.as_str());
//cmd= re.replace_all(cmd.as_str(),"").to_string();
let cmd_0=cmd.chars().nth(0).unwrap();
//cmd.remove(0);
//V.push(codeV); //Compile error
V.push(None); //OK
}
//V
}
fn main() {
parse("m {abcd} l {efgh}");
}
Though I don't have any workaround.
regex's captures refer to the string they matched for efficiency. This means they can't outlive that string, as the match groups are essentially just offsets into that string.
Since the strings you match are created in the loop body, this means captures can't escape the loop body.
Aside from not creating strings in the loop body (or even the function), the solution / workaround is to convert your capture groups to owned data and store that: instead of trying to return a vector of captures, extract from the capture the data you actually want, convert it to an owned String (or tuple thereof, or whatever), and push that onto your vector.
e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0107333e30f831a418d75b280e9e2f31
you can use cmd.clone().as_str() if you not sure the value has borrowed or no
I'm trying to insert a value into a HashMap based on another value in the same HashMap, like so:
use std::collections::HashMap;
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", 1);
let some_val = some_map.get("a").unwrap();
if *some_val != 2 {
some_map.insert("b", *some_val);
}
}
which gives this warning:
warning: cannot borrow `some_map` as mutable because it is also borrowed as immutable
--> src/main.rs:10:9
|
7 | let some_val = some_map.get("a").unwrap();
| -------- immutable borrow occurs here
...
10 | some_map.insert("b", *some_val);
| ^^^^^^^^ --------- immutable borrow later used here
| |
| mutable borrow occurs here
|
= note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
= warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
= note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
If I were instead trying to update an existing value, I could use interior mutation and RefCell, as described here.
If I were trying to insert or update a value based on itself, I could use the entry API, as described here.
I could work around the issue with cloning, but I would prefer to avoid that since the retrieved value in my actual code is somewhat complex. Will this require unsafe code?
EDIT
Since previous answer is simply false and doesn't answer the question at all, there's code which doesn't show any warning (playground)
Now it's a hashmap with Rc<_> values, and val_rc contains only a reference counter on actual data (number 1 in this case). Since it's just a counter, there's no cost of cloning it. Note though, that there's only one copy of a number exists, so if you modify a value of some_map["a"], then some_map["b"] is modified aswell, since they refer to a single piece of memory. Also note, that 1 lives on stack, so you better consider turn it into Rc<Box<_>> if you plan to add many heavy objects.
use std::collections::HashMap;
use std::rc::Rc;
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", Rc::new(1));
let val_rc = Rc::clone(some_map.get("a").unwrap());
if *val_rc != 2 {
some_map.insert("b", val_rc);
}
}
Previous version of answer
Hard to tell what exactly you're looking for, but in this particular case, if you only need to check the value, then destroy the borrowed value, before you update the hashmap. A dirty and ugly code would be like this:
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", 1);
let is_ok = false;
{
let some_val = some_map.get("a").unwrap();
is_ok = *some_val != 2;
}
if is_ok {
some_map.insert("b", *some_val);
}
}
This question already has an answer here:
Mutating the same data in multiple 'static closures
(1 answer)
Closed 4 years ago.
I'm using the libpulse_binding library, and I'm trying to obtain a sequence of SinkInputInfos from the get_sink_input_info_list function:
pub fn get_sink_input_info_list<F>(
&self,
callback: F,
) -> Operation<dyn FnMut(ListResult<&SinkInputInfo>)>
where
F: FnMut(ListResult<&SinkInputInfo>) + 'static,
The function takes a callback and calls it once for each SinkInputInfo it produces. I'm trying to collect all those SinkInputInfos into a single list so I can get a clearer view of the state of the world. Irritatingly, SinkInputInfo doesn't implement Copy or Clone, so I made a custom struct and implemented From to get the useful information out of the SinkInputInfo:
struct StreamInfo {
readable_name: String,
binary_name: String,
pid: String,
}
impl From<&pulse::context::introspect::SinkInputInfo<'_>> for StreamInfo {
fn from(info: &pulse::context::introspect::SinkInputInfo) -> Self {
let name = info.proplist.gets("application.name").unwrap();
let binary = info.proplist.gets("application.process.binary").unwrap();
let pid = info.proplist.gets("application.process.id").unwrap();
StreamInfo {
readable_name: name,
binary_name: binary,
pid: pid,
}
}
}
However, this doesn't seem to work. I have the following code:
let mut sink_infos: Vec<StreamInfo> = Vec::new();
let op = introspector.get_sink_input_info_list(|result| match result {
pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
pulse::callbacks::ListResult::End => {},
pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
});
but it doesn't compile:
error[E0373]: closure may outlive the current function, but it borrows `sink_infos`, which is owned by the current function
--> src/bin/play-pause.rs:49:52
|
49 | let op = introspector.get_sink_input_info_list(|result| match result {
| ^^^^^^^^ may outlive borrowed value `sink_infos`
50 | pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
| ---------- `sink_infos` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/bin/play-pause.rs:49:14
|
49 | let op = introspector.get_sink_input_info_list(|result| match result {
| ______________^
50 | | pulse::callbacks::ListResult::Item(info) => sink_infos.push(info.into()),
51 | | pulse::callbacks::ListResult::End => {},
52 | | pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
53 | | });
| |______^
help: to force the closure to take ownership of `sink_infos` (and any other referenced variables), use the `move` keyword
|
49 | let op = introspector.get_sink_input_info_list(move |result| match result {
| ^^^^^^^^^^^^^
tldr: the closure has to have the 'static lifetime because libpulse_binding says so (presumably because it gets handed to the PulseAudio C API, which can then do whatever it likes with it), but sink_infos is not 'static, and the closure has to borrow sink_infos in order to append to it, which makes the closure not 'static, IIUC.
How can I make a Vec (or any container, I'm not fussy) of SinkInputInfos given a 'static closure that gets called repeatedly with a &SinkInputInfo?
The basic problem here is that you're running into Rust's borrowing rules:
Given an object T, it is only possible to have one of the following:
Having several immutable references (&T) to the object (also known as aliasing).
Having one mutable reference (&mut T) to the object (also known as mutability).
You are trying to keep a reference &Vec to your Vec (so you can use it later) whilst simultaneously trying to add things to it in a closure (i.e. an &mut Vec). Rust doesn't know that you won't try to use the &Vec while the closure is using the &mut Vec, so it doesn't let you create a &mut Vec in the closure while there's still a &Vec hanging around outside the closure.
The next best thing you can do is to use an Rc. This will allow you to sidestep the compiler's borrow-checking and instead defer it to runtime. However: this means that if you try to violate the borrowing rules while your program is running, it will panic instead of being a compile-time error!
For the most part, you can treat the Rc<Vec<_>> the same as a normal Vec, since Rc implements Deref.
Since you also want to be able to mutate the Vec in order to add things to it, you also need to put it in a RefCell. This will put a lock around the Vec, making sure that you only have one &mut Vec available at once, and that if you have an &Vec, you can't have a &mut Vec (again, if you try to violate the rules, your program will panic). You can use the .borrow() and .borrow_mut() methods on RefCell to get shared and mutable references to the Vec (there are also try_* variants of these methods, if you can do something sensible if a borrow is not possible).
If you didn't use a RefCell, you would only be able to obtain immutable/shared references (&Vec) from the Rc (unless you only had one Rc, but then you wouldn't need an Rc!)
Try something like the following:
use std::cell::RefCell;
use std::rc::Rc;
let sink_infos: Rc<RefCell<Vec<StreamInfo>>> = Rc::new(RefCell::new(Vec::new()));
let sink_infos2 = sink_infos.clone(); // Create a new Rc which points to the same data.
let op = introspector.get_sink_input_info_list(move |result| match result {
pulse::callbacks::ListResult::Item(info) => sink_infos2.borrow_mut().push(info.into()),
pulse::callbacks::ListResult::End => {},
pulse::callbacks::ListResult::Error => panic!("Error getting sink input info"),
});