2016-03-01 6 views
8

Я пытаюсь написать функцию, возвращающую закрытую коробку, которая может работать с ссылками на типы с любым временем жизни . При написании конкретного экземпляра все работает нормально. Но при написании общей версии я сталкиваюсь с проблемами времени.Вышеуказанная черта Ограниченная продолжительность жизни и закрытие ящиков с закрытыми ящиками

struct Parameter<'a> { 
    s: &'a str, 
} 

fn main() { 
    let closure = generate_closure_gen(); 
    let string = String::from("Hello World!"); 
    let parameter = Parameter { s: &string }; // Error: string does not live long enough 
    closure(&parameter); 
} 

// This one works fine 
// Desugared version for Box<Fn(&Parameter)> 
fn generate_closure() -> Box<for <'a, 'r> Fn(&'r Parameter<'a>)> { 
    Box::new(|c: &Parameter| {}) 
} 

// This one gives lifetime errors 
fn generate_closure_gen<C>() -> Box<Fn(&C)> { 
    Box::new(|c: &C| {}) 
} 

Я не понимаю, почему закрытие нужен параметр типа, чтобы жить дольше, чем (нет хранения или что-нибудь ...). И он работает для не-родовой версии с HRTB, просто кажется, что это должно быть возможно, чтобы он работал с общей версией.
Кроме того, если я пытаюсь написать конкретную версию с помощью универсальной версии, я получаю ошибку типа

// Desugared version for Box<Fn(&Parameter)> 
fn generate_closure_2() -> Box<for <'a, 'r> Fn(&'r Parameter<'a>)> { 
    generate_closure_gen() 
} 

src/main.rs:22:5: 22:27 error: mismatched types: 
expected `Box<for<'r, 'r> core::ops::Fn(&'r Parameter<'r>) + 'static>`, 
    found `Box<for<'r> core::ops::Fn(&'r _) + 'static>` 
(expected concrete lifetime, 
    found bound lifetime parameter) [E0308] 
src/main.rs:22  generate_closure_gen() 
        ^~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:22:5: 22:27 help: run `rustc --explain E0308` to see a detailed explanation 

Любую идею о том, как сделать эту работу?

(playpen link)

+1

Компилятор, по-видимому, не вставляет 'for <'a>' сам по себе, если задан общий параметр. Если вы не получите удовлетворительного объяснения, вы можете отправить ссылку на этот вопрос на https://www.reddit.com/r/rust/, где разработчики Rust чаще всего будут болтаться. –

+0

Мой ответ был явно неправильным, поэтому я удалил его. Но ваш комментарий объясняет, что именно вы имеете в виду: «Я не понимаю, почему закрытие требует, чтобы параметр типа жил дольше, чем он (нет никакого хранилища или чего-то еще ...). И он работает для не-универсальной версии с HRTB, он просто чувствует, что должно быть возможно заставить его работать с общей версией ». - @ Валден – aSpex

ответ

6

Параметры типа имеют срок службы связаны. Эта привязана к жизни - это кратчайший из всех параметров жизни исполнителя. Вы опущено его на generate_closure_gen, поэтому компилятор сделать вывод, но если мы явно писал его, определение функции будет выглядеть следующим образом:

fn generate_closure_gen<'a, C: 'a>() -> Box<Fn(&C)> { 
    Box::new(|c: &C| {}) 
} 

внесении этих изменений не решает нашу проблему, хотя.

Чтобы понять, почему, нам нужно выяснить, что такое C. Вы называете замыкание &'y Parameter<'x>, а замыкание принимает for<'b> &'b C, поэтому C - Parameter<'x>. Parameter<'x> имеет параметр продолжительности жизни, который будет влиять на срок службы на C.

Параметры времени жизни в общих функциях должны быть заменены временем жизни, которое начинается перед вызовом функции. В этом случае это означает, что время жизни любого C, которое мы передаем закрытию, должно быть действительным до вызова generate_closure_gen. Это потому, что C привязан к определенной продолжительности жизни, а не к жизни; то есть когда C составляет Parameter<'x>, 'x должен быть известен заранее; мы не можем иметь разные 'x каждый раз, когда мы вызываем замыкание. Другими словами, то, что вы хотели бы иметь что-то вроде этого:

fn generate_closure_gen<C: for<'a> 'a>() -> Box<Fn(&C)> { 
    Box::new(|c| {}) 
} 

Но, к сожалению, это не является законным, как Руст 1.7.