У меня есть короткий пример увеличения вектора путем деления и покорения. Очень простой, я просто не могу получить правильные сроки жизни. Я уверен, что это связано с временем жизни аргумента &'s mut
и возвратом жизни TaskResult<'s>
, но я не уверен, как заставить его работать.Пожизненные проблемы передачи & mut для функционирования и возврата закрытия
fn main() {
let mut data = vec![1,2,3,4,5,6,7,8,9];
let t = inc_vec(data.as_mut_slice());
}
pub type MyClosure<'s> = FnMut() -> TaskResult<'s> + Send + 's;
pub enum TaskResult<'s> {
Done(usize),
Fork(Vec<Box<MyClosure<'s>>>),
}
fn inc_vec<'s>(data: &'s mut [usize]) -> TaskResult {
if data.len() <= 4 {
inc_vec_direct(data)
} else {
inc_vec_fork(data)
}
}
fn inc_vec_fork<'s>(data: &'s mut [usize]) -> TaskResult<'s> {
let mid = data.len()/2;
let (l,r) = data.split_at_mut(mid);
let task_l: Box<MyClosure<'s>> = Box::new(move || {
inc_vec(l)
});
let task_r: Box<MyClosure<'s>> = Box::new(move || {
inc_vec(r)
});
TaskResult::Fork(vec![task_l, task_r])
}
fn inc_vec_direct(data: &mut [usize]) -> TaskResult {
for d in data {
*d += 1;
}
TaskResult::Done(1)
}
И это дает мне следующую ошибку (усеченный так же ошибка производится дважды, один раз для task_l
и один раз для task_r
):
src/main.rs:26:17: 26:18 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements
src/main.rs:26 inc_vec(l)
^
src/main.rs:25:55: 27:6 note: first, the lifetime cannot outlive the lifetime as defined on the block at 25:54...
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
src/main.rs:27 });
src/main.rs:26:17: 26:18 note: ...so that closure can access `l`
src/main.rs:26 inc_vec(l)
^
src/main.rs:21:62: 33:2 note: but, the lifetime must be valid for the lifetime 's as defined on the block at 21:61...
src/main.rs:21 fn inc_vec_fork<'s>(data: &'s mut [usize]) -> TaskResult<'s> {
src/main.rs:22 let mid = data.len()/2;
src/main.rs:23 let (l,r) = data.split_at_mut(mid);
src/main.rs:24
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
...
src/main.rs:25:38: 27:7 note: ...so that trait type parameters matches those specified on the impl (expected `TaskResult<'_>`, found `TaskResult<'s>`)
src/main.rs:25 let task_l: Box<MyClosure<'s>> = Box::new(move || {
src/main.rs:26 inc_vec(l)
src/main.rs:27 });
Там должно быть просто исправить это. Все, что я хочу сказать, это то, что я возвращаю вектор замыканий, которые имеют изменяемые ссылки на части входного среза. Я предполагаю, что я должен отметить время жизни закрытия короче, чем время жизни среза данных, просто не уверен, как это сделать.
Здесь нет простого исправления, потому что по сути небезопасно передавать ссылки на потоки, поскольку родительский поток, которому принадлежит эта ссылка, может завершаться перед другими потоками, делая недействительным то, на что указывают ссылки в дочерних элементах. Вам придется немного изменить свой дизайн. Посмотрите на http://stackoverflow.com/questions/26477757/how-do-you-send-slices-of-a-vec-to-a-task-in-rust для возможных обходных решений. –
@ FilipeGonçalves это не совсем правильно, потому что есть механизм, который гарантирует, что ссылка не переживет родительский стековый фрейм (см. ['Thread :: scoped'] (http://doc.rust-lang.org/ std/thread/fn.scoped.html)), даже если он передан в другой поток. В этом конкретном случае даже нет потоков. –