2017-12-30 26 views
1

を使用している場合にのみ:値は「十分に長く住んでいない」が、私は、コンパイルするには、次の単純化されたコードを取得しようとしている関数ポインタ

type FunctionType<'input> = fn(input_string: &'input str) -> Result<(), &'input str>; 

fn okay<'input>(_input_string: &'input str) -> Result<(), &'input str> { 
    Ok(()) 
} 

fn do_stuff_with_function(function: FunctionType) { 
    let string = String::new(); 
    match function(string.as_str()) { 
     Ok(_) => {}, 
     Err(_) => {}, 
    } 

} 

fn main() { 
    do_stuff_with_function(okay);  
} 

遊び場は、不平を言う:

error[E0597]: `string` does not live long enough 
    --> src/main.rs:13:20 
    | 
13 |  match function(string.as_str()) { 
    |     ^^^^^^ does not live long enough 
... 
18 | } 
    | - borrowed value only lives until here 
    | 
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 11:1... 
    --> src/main.rs:11:1 
    | 
11 |/fn do_stuff_with_function(function: FunctionType) { 
12 | |  let string = String::new(); 
13 | |  match function(string.as_str()) { 
14 | |   Ok(_) => {}, 
... | 
17 | |  
18 | | } 
    | |_^ 

私は他の状況でエラーが発生する理由を理解しています:do_stuff_with_functionが実行されている間だけstringが存続しますが、の呼び出しの値は入力値valと同じですすなわち、stringである。私は両方のブランチのため()を返し、その後、関数呼び出しの結果をmatch

  1. はしかし、私は三点に困惑しています。無条件で放棄された場合、価値の生涯はfunctionによって返されるのはなぜですか?

  2. パラメータfunctionへの呼び出しを、okay(同一の署名を持つ)への直接参照で置き換えると、苦情なしでコンパイルされます。
  3. エラーメッセージには、必要な有効期間が実際の有効期間と同じであることが示されています(ただし、完全に記載されていません)。

答えて

2

TL; DR:使用the for<'a> syntaxは、それが使われている文脈から1を取るのではなく、機能のための具体的な寿命を持っています。 do_stuff_with_functionの引数に


生涯エリジオンは、ここで何が起こっているのか非表示になります。関数の引数で宣言された。この寿命は「私は後に出てくるだろういくつかのランダムな寿命が短い」という意味ではありません

fn do_stuff_with_function<'a>(function: FunctionType<'a>) { 

ではなく、「すでにこれを呼び出した時点で存在して寿命:あなたの実際の寿命があります関数"。

これらのライフタイムアノテーションはワイルドカードではなく、値がどこから来たのか、どこに行くのかを追跡する識別子によく似ています。彼らはこのような状況を明確にするために、例えば、使用することができます。

fn do_stuff_with_function<'a>(function: FunctionType<'a>, t: &'a str) { 
    match function(t) { 
     Ok(_) => {}, 
     Err(_) => {}, 
    } 
} 

fn main() { 
    let string = String::new(); 
    do_stuff_with_function(okay, string.as_str());  
} 

しかし、問題はルーストに解けるですが、ただ、より高度な構文を必要とします。説明の目的のために、まず、のに変更してみましょう:「&'a strを取る機能(など)のように見える何もすることができたすべての固有Fためdo_stuff_with_functionのコピーを作成することを意味し

fn do_stuff_with_function<'a, F>(function: F) where F: Fn(&'a str) -> Result<(), &'a str> { 

これはあなたのコードと本質的に同じです(+閉鎖を許可します)。しかし、私はまだ生涯をdo_stuff_with_function<'a>の呼び出しに結びつけて命名しなければなりませんでした。だからここ

freaky type magicです:

for<'a>構文を使用して Fnの定義に do_stuff_with_functionから寿命の定義を移動することができます
fn do_stuff_with_function<F>(function: F) where F: for<'a> Fn(&'a str) -> Result<(), &'a str> { 

。この方法では、do_stuff_with_function引数ではなく、Fに固有です。

+0

これは私の場合に有効です!私はまだ私の元の質問のポイント(1)がコンパイラを満足させるのに十分でない理由を確信しています。あなたがエイリアスをインライン化しなければならないのは悲しいです(私が持っている本当のものはむしろ巨大です)。奇妙なタイプの魔法です。 – stuffy

+2

@stuffyでは、エイリアスをインライン化する必要はありません。 'for <'_>'を追加することができます。 [遊び場](https://play.rust-lang.org/?gist=bbd442124db421e7201baa5b29ea7829&version=stable) – red75prime

+2

また、タイプエイリアスから '<'input>'を削除することもできます。 'FunctionType = fn(input_string:&str) - > Result <()、&str>;' Lifetime elisionは正しいことを行います。 – red75prime

関連する問題