2013-10-21 6 views
4

rust 0.8을 사용하고 있습니다.클로저 내부에서 on-heap 함수 인수를 호출합니다.

는 왜 나는이 작업을 수행 할 수 있는지 :

fn add(num: ~int) -> ~fn(int) -> int { |x| 
    *num + x 
} 

만하지이 :

두 번째는, "오류와 함께 실패
fn outer(num: ~int) -> ~fn(int) -> int { |x| 
    *inner(num) + x 
} 

fn inner(num: ~int) -> ~int { 
    num 
} 

: 힙에서 캡처 된 외부 변수 밖으로 이동할 수 없습니다 폐쇄". 함수를 특별하게 호출하는 이유는 무엇입니까?

정적 분석이 잡히지 않을 박스 함수로 내부 함수가 더러운 것을 수행 할 염려가 있습니까?

+2

정답이 아니므로 댓글로 추가하겠습니다. https://github.com/mozilla/rust/wiki/Doc-under-construction-FAQ –

답변

3

문제는 클로저를 두 번 호출 할 가능성이 있습니다. 첫 번째 실행에서 캡처 된 변수 numinner으로 이동됩니다. 즉, 클로저의 환경 밖으로 이동합니다. 그런 다음 두 번째 호출에서 num이 있던 위치가 이제는 유효하지 않게되고 (메모리가 이동 된 이후에) 메모리 안전이 손상됩니다. 잘못된 하나, 하나가 inner 전화로 빌린 포인터 뒤에서 self.num를 이동하려고 :

구체적으로, 하나는 (약)

struct Closure { // stores all the captured variables 
    num: ~int 
} 

impl Closure { 
    fn call(&self, x: int) -> int { 
     // valid: 
     *self.num + x 

     // invalid: 
     // *inner(self.num) + x 
    } 
} 

는 희망이 그것을 만드는 명확로 폐쇄 간주 할 수 있습니다 (그 이후에는 완전히 num 필드와의 연결이 끊어집니다). 가능한 경우 self은 유효하지 않은 상태로 남습니다. 예를 들어 self.num의 소멸자가 호출되어 메모리를 해제합니다 (메모리 안전을 위반 함). 이것의


한 해상도로 위 call의 유형을 조정 (그것의 가장 기본적인에서)가 찬성 제거 할 수 있기 때문에, 구현하지만 컴파일러 플래그 뒤에 숨겨져있다 "기능을 한 번"입니다 fn call(self, x: int), 즉 클로저가 self으로 이동하면 (즉, callself 및 해당 필드를 소유하고 있기 때문에) 환경 밖으로 이동할 수 있고 함수가 정적으로 한 번만 호출 될 수 있다는 것을 의미합니다 *.

* 클로저의 환경이 소유권을 이전하지 않는 경우 (예 : 그것이 struct Env { x: int } 인 경우.

+0

함수는 동일한 클로저를 가지고있는 closure가 동일한 수명을 갖는 한 사용됩니다. 평생 매개 변수를 추가하고 작동시키지 않는 이유는 무엇입니까? 함수가 변경 가능하고 멱등수가 아니라면 함수를 여러 번 호출하는 것에 대해 본질적으로 위험한 것은 없습니다. 또한 함수를 내부로 이동 시켜서 클로저의 환경 밖으로 이동시키는 이유는 무엇입니까? 클로저가 해제 될 때부터 안전하다고 생각됩니다. 동일한 환경에 있어야합니다. – nnythm

+0

그것이 문제가되는 폐쇄가 아닙니다. 그것은'num'입니다. 'num' 캡처가 돌아 다니고'~'포인터는 첫 번째 호출 이후에 해제 될 것입니다. (왜냐하면'inner'로 옮겨지기 때문에 클로저의 환경은'num'의 제어와 소유권을 잃습니다. 'num'이 떨어지면 "choose"로 간다.) 즉, 두 번째 (세 번째, 네 번째 ...)는'num'을 처리 할 때 이미 해제 된 메모리를 사용하려고 시도 할 것입니다. – huon