2014-09-05 4 views
3

Этот код:Как вы комбинируете времена жизни в ржавчине?

struct Foo<'a> { 
    value: Option<&'a int>, 
    parent: Option<&'a Foo<'a>> 
} 

impl<'a> Foo<'a> { 
    fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> { 
    return Foo { value: Some(other), parent: Some(self) }; 
    } 
} 

fn main() { 
    let e = 100i; 
    { 
    let f = Foo { value: None, parent: None }; 
    let g:Foo; 
    { 
     g = f.bar(&e); 
    } 
    // <--- g should be valid here 
    } 
    // 'a of f is now expired, so g should not be valid here. 

    let f2 = Foo { value: None, parent: None }; 
    { 
    let e2 = 100i; 
    let g:Foo; 
    { 
     g = f2.bar(&e2); 
    } 
    // <--- g should be valid here 
    } 
    // 'b of e2 is now expired, so g should not be valid here. 
} 

Не удается скомпилировать с ошибкой:

<anon>:8:30: 8:35 error: cannot infer an appropriate lifetime due to conflicting requirements 
<anon>:8  return Foo { value: Some(other), parent: Some(self) }; 
             ^~~~~ 
<anon>:7:3: 9:4 note: consider using an explicit lifetime parameter as shown: fn bar<'a, 'b>(&'a self, other: &'b int) -> Foo<'b> 
<anon>:7 fn bar<'a, 'b, 'c: 'a + 'b>(&'a self, other:&'b int) -> Foo<'c> { 
<anon>:8  return Foo { value: Some(other), parent: Some(self) }; 
<anon>:9 } 

(манеж: http://is.gd/vAvNFi)

Это, очевидно, надуманный пример, но это то, что я хочу сделать время от времени.

Итак ...

1) Как вы совмещаете времена жизни? (т. е. вернуть a Foo, который имеет время жизни не менее a или b, что когда-либо меньше)

2) Есть ли способ написать тесты на сбой компиляции ресурса? (например, попытаться составить # [тест], который использует функцию в неправильном направлении, и не с пожизненной ошибкой)

+0

(BTW, код в пост не компилируется и не соответствует коду в ссылке манеж.) – huon

+0

@dbaupp мой плохой , Исправлено. – Doug

ответ

8

Границы 'c: 'a + 'b означает, что 'c является как минимум 'a и до 'b. Однако в этом случае значение Foo действительно для кратчайшего из 'a и 'b: как только данные, стоящие за любой ссылкой, выходят за рамки, все Foo должно быть признано недействительным. (Это говорит, что данные, которые действительны для 'c действует в союз из 'a и 'b.)

В более конкретном плане, скажем 'b = 'static, то 'c: 'a + 'static означает, что 'c также должен быть 'static, так что возвращаемое значение будет Foo<'static>. Это явно не так, как если бы это было «обновление» ограниченной ссылки 'aself в том, что длится вечно.

Правильное поведение здесь занимает пересечение времен жизни: Foo действителен только в том случае, если оба параметра функции действительны. Операция пересечения просто помечая ссылки с тем же именем:

fn bar<'a>(&'a self, other: &'a int) -> Foo<'a> 
+0

Я отредактировал свой ответ, чтобы заменить «самый большой» (объединение) «наименьшим» (пересечением). Но, поскольку bar является методом здесь, не лучше ли было бы опустить параметр «a» lifetime в методе и вместо этого использовать '' a' из 'impl'? Я знаю, что он вызывает ошибки при реализации признака (параметры жизненного цикла должны соответствовать тем, которые определены в черте), но это просто простой 'impl', поэтому оба варианта работают. –

+0

@ FrancisGagné: По крайней мере, я согласен с тобой. Кажется, нет необходимости в каких-либо новых параметрах жизни для функции. – sellibitze

3

Удалить все параметры limetime на bar и использовать параметр 'a пожизненных из impl вместо.

impl<'a> Foo<'a> { 
    fn bar(&'a self, other:&'a int) -> Foo<'a> {     // ' 
    return Foo { value: Some(other), parent: Some(self) }; 
    } 
} 

'a будет выведен компилятором быть наименьшим срок службы, в котором все ссылки действительны.

Смежные вопросы