2017-01-01 4 views
1

왜이 평생 오류가 없습니다 :변경할 수없는 참조 대신 구조체에서 변경 가능한 참조를 사용하면 평생 오류가 발생하는 이유는 무엇입니까?

fn main() { 
    struct f<'a> { 
     x: &'a i32, 
    } 
    impl<'a, 'b> f<'a> { 
     fn get(&'b self) -> &'a i32 { 
      self.x 
     } 
    } 
    let x = 3; 
    let y = f { x: &x }; 
    let z = f::get(&y); 
} 

을하지만이

fn main() { 
    struct f<'a> { 
     x: &'a mut i32, 
    } 
    impl<'a, 'b> f<'a> { 
     fn get(&'b self) -> &'a i32 { 
      self.x 
     } 
    } 
    let mut x = 3; 
    let y = f { x: &mut x }; 
    let z = f::get(&y); 
} 

이 오류가 있습니다

error[E0312]: lifetime of reference outlives lifetime of borrowed content... 
--> src/main.rs:7:13 
    | 
7 |    self.x 
    |    ^^^^^^ 
    | 
note: ...the reference is valid for the lifetime 'a as defined on the block at 6:36... 
--> src/main.rs:6:37 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |         ^
note: ...but the borrowed content is only valid for the lifetime 'b as defined on the block at 6:36 
--> src/main.rs:6:37 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |         ^
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32 
--> src/main.rs:6:9 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |  ^
+0

정확히 모르겠지만, f의 x를 더 이상 변경할 수 없으므로 두 번째 예제가 실패하는 것이 중요하다고 생각합니다. – torkleyy

+0

주 :'f'는'F'이어야하며,'y.get()'을 직접 호출 할 수 있습니다 ... 나는이 질문을 정말 좋아합니다! –

+0

와우, 시간이 좀 걸렸지 만 나는 마침내 여기에서 무슨 일이 일어나고 있었는지 정확히 이해하고이 토끼 구멍을 내려가는 것이 정말 멋지다고 생각한다. 다시 질문 주셔서 감사합니다! –

답변

2

내가 먼저 더 관용적 녹에서 재구성 것이다 :

struct F<'a> { 
    x: &'a mut i32, 
} 

impl<'a> F<'a> { 
    fn get<'b>(&'b self) -> &'a i32 { 
     self.x 
    } 
} 

fn main() { 
    let mut x = 3; 
    let y = F { x: &mut x }; 
    let z = y.get(); 
} 

이 이전과 같은 오류가 있습니다

lifetime of reference outlives lifetime of borrowed content 

가 왜 녹 컴파일러는 get의 이행을 거부 않습니다를? 그것은 수 있기 때문에 :

을 다음 get 컴파일 가정, 완벽하게 합리적인 main입니다 :

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let a = y.get(); 
    let b = y.x; 

    println!("{} {}", a, b); 
} 

그러나 get 컴파일이 잘 될 것된다면 :

  • a 빌려하지 않습니다 y 수명이 다르기 때문에
  • b "소모"y (이동 f 롬 y.x)하지만 우리는

후 다시 사용하지 않습니다 그래서 모든 것을 우리가 지금 &i32&mut i32x를 가리키는 두를 가지고 있다는 것을 제외하고는, 괜찮습니다.

참고 : 컴파일하려면 을 get : unsafe { std::mem::transmute(&*self.x) } 안에 사용할 수 있습니다. 무서운, 응?

Aliasing XOR Mutability

녹 때마다 당신이 뭔가를 수정하는 것을 보장함으로써 가비지 컬렉션없이 메모리의 안전을 달성 : 차용 검사 알고리즘의 핵심


는 녹의 메모리 안전이 내장되어있는 초석입니다 어떤 관찰자도 매달릴 수있는 어떤 것을 참조 할 수 없다.

이, 회전에, 우리가 해석 할 수 있습니다 :

앨리어싱 참조
  • &T; 그것은 Copy
  • &mut T으로 고유 한 참조; 고유성을 위반했기 때문에 Copy이 아니지만 이동 될 수 있습니다.

이 차이점이 여기에 우리를 구해줍니다.

&mut T가 복사 될 수 없기 때문에, 유일한 방법 &T (또는 &mut T)이 재 수행하는 조조 &mut T 행에 가고 : 간접 참조를하고 그 결과에 대한 참조를 취할.

이것은 컴파일러에서 암시 적으로 수행됩니다. 다소 더 나은 오류 메시지를 수동으로 수행한다 :

fn get<'b>(&'b self) -> &'a i32 { 
    &*self.x 
} 
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
--> <anon>:7:9 
    | 
7 |   &*self.x 
    |   ^^^^^^^^ 
    | 
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32 
--> <anon>:6:5 
    | 
6 |  fn get<'b>(&'b self) -> &'a i32 { 
    | ^

왜 평생을 추론 할 수없는 이유는 무엇입니까? 재구 성의 수명은 'b에 의해 제한되기 때문에, 우리는 'a을 요구하고 있으며이 둘 사이에는 아무 관계도 없습니다! 그 결과 삶 (우리를 방지가 F::x를 통해 변경 가능한 참조를 사용하는) 동안 인스턴스 F해야 빌린 할을 보장하기 때문에 그런데

이 여기 실수에서 우리를 절약 것입니다.

컴파일러 힌트에 따라, 그리고 &'b i32 작품을 반환

... 그리고 컴파일에서 위의 main 방지 :

impl<'a> F<'a> { 
    fn get<'b>(&'b self) -> &'b i32 { 
     &*self.x 
    } 
} 

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let a = y.get(); 
    let b = y.x; 

    println!("{} {}", a, b); 
} 
는 처음 main가 문제없이 컴파일 할 수 있습니다 그러나
error[E0505]: cannot move out of `y.x` because it is borrowed 
    --> <anon>:16:9 
    | 
15 |  let a = y.get(); 
    |    - borrow of `y` occurs here 
16 |  let b = y.x; 
    |  ^move out of `y.x` occurs here 

:

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let z = y.get(); 

    println!("{}", z); 
} 

인쇄물 3.