2017-12-30 44 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의 실행 시간 동안 만 지속되지만, 은 function의 입력 값과 동일한 수명의 참조를 포함하는 호출의 값을 반환합니다. 즉, string.

그러나, 나는 3 점에 혼란 스러워요 :

  1. 내가 함수 호출의 결과를 match, 다음 두 가지에 대한 ()을 반환합니다. 무조건 버려지는 경우 가치가 평생 function에 의해 반환되는 이유는 무엇입니까?
  2. function에 대한 호출을 okay (동일한 서명이 있음)에 대한 직접 참조로 바꾸면 불만없이 컴파일됩니다.
  3. 오류 메시지는 필요한 수명이 이미 실제 수명과 동일하다는 것을 나타냅니다 (단, 명백한 것은 아니지만).

답변

2

TL; DR : 사용 the for<'a> syntax 그것이 사용되는 문맥에서 하나를 수행하기보다는, 기능에 대한 특정의 수명을 가지고있다. 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>;'평생 엘 리젠트는 올바른 일을 할 것입니다. – red75prime