2016-12-21 9 views
1

Основываясь на моем понимании времен жизни, если вызывающий объект задает время жизни для параметра, я могу вернуть тип с этим временем жизни.Почему я не могу вернуть fmt :: Аргументы <'a> от & 'a T?

Это работает, даже с элизии:

pub fn substr(s: &str) -> &str { 
    &s[0..1] 
} 

pub fn substr_ex<'a>(s: &'a str) -> &'a str { 
    &s[0..1] 
} 

Но это не делает:

use std::fmt::Arguments; 

pub fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> { 
    format_args!("{:?}", t) 
} 
error: borrowed value does not live long enough 
    --> <anon>:16:18 
    | 
16 |  format_args!("{:?}", t) 
    |     ^^^^^^ does not live long enough 
17 | } 
    | - temporary value only lives until here 
    | 
    = note: borrowed value must be valid for the lifetime 'a as defined on unknown free region bounded by scope CodeExtent(38/CallSiteScope { fn_id: NodeId(42), body_id: NodeId(92) })... 

error: `t` does not live long enough 
    --> <anon>:16:26 
    | 
16 |  format_args!("{:?}", t) 
    |      ^does not live long enough 
17 | } 
    | - borrowed value only lives until here 
    | 
    = note: borrowed value must be valid for the lifetime 'a as defined on unknown free region bounded by scope CodeExtent(38/CallSiteScope { fn_id: NodeId(42), body_id: NodeId(92) })... 

Является ли это ошибка? Или я не понимаю времена жизни?

Playpen: https://play.rust-lang.org/?gist=5a7cb4c917b38e012f20c771893f8b3b&version=nightly

+2

Ваши первые два примера возвращают ссылку, поэтому они не очень сопоставимы с последней, которая возвращает принадлежащий ему объект. – ljedrz

ответ

2

Чтобы понять, что происходит, давайте посмотрим на macro-expanded version:

fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> { 
    ::std::fmt::Arguments::new_v1({ 
             static __STATIC_FMTSTR: 
              &'static [&'static str] = 
              &[""]; 
             __STATIC_FMTSTR 
            }, 
            &match (&t,) { 
             (__arg0,) => 
             [::std::fmt::ArgumentV1::new(__arg0, 
                    ::std::fmt::Debug::fmt)], 
            }) 
} 

Это помогает объяснить первую ошибку:

error: borrowed value does not live long enough 
    --> src/main.rs:9:36 
    | 
9 |         &match (&t,) { 
    |         ^temporary value created here 
... 
15 | } 
    | - temporary value only lives until here 
    | 
note: borrowed value must be valid for the lifetime 'a as defined on the block at 4:72... 
    --> src/main.rs:4:73 
    | 
4 | fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> { 
    |                  ^

В частности, ArgumentV1 создается в стеке и делается ссылка на него. Вы не можете вернуть эту ссылку из функции.

Вторая ошибка:

error: `t` does not live long enough 
    --> src/main.rs:9:44 
    | 
9 |         &match (&t,) { 
    |           ^does not live long enough 
... 
15 | } 
    | - borrowed value only lives until here 
    | 
note: borrowed value must be valid for the lifetime 'a as defined on the block at 4:72... 
    --> src/main.rs:4:73 
    | 
4 | fn as_format_arg<'a, T: 'a + ?Sized + Debug>(t: &'a T) -> Arguments<'a> { 
    |                  ^

Обратите внимание, что format! family of macros doesn't take their arguments by value; они автоматически вставляют ссылку. Вы бы не хотели, чтобы println! владел своим значением !.

Это означает, что напечатанное значение фактически &&'a T - в ссылку на t значение стека выделяется! Опять же, вы не можете вернуть ссылку на что-то, выделенное в стеке.

if the caller of a function specifies a lifetime on a parameter, I can return a type with that lifetime.

Это на полпути. Вы можете возвратить только возврат части этого входного параметра. Вы не можете создать совершенно новое значение и вернуть его с этим временем жизни.

+0

Ох .. сгенерированный код показывает, что происходит .. Спасибо. Вместо этого я решил использовать FormatArg <'a>. – kdy