Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Eau de Cologne

[Rust] Lifetime elision 본문

rkgk

[Rust] Lifetime elision

cologne 2023. 10. 6. 17:51

다음 코드를 생각해봅시다.

  1. fn ref_idx(v: &mut [i32], i: usize, j: usize) -> (&mut i32, &mut i32) {
  2.     assert!(i != j && i < v.len() && j < v.len());
  3.     let ptr = v.as_mut_ptr();
  4.     unsafe { (&mut *(ptr.add(i)), &mut *(ptr.add(j))) }
  5. }

이후,

  1. let mut v = vec![1, 2];
  2. let (i, j) = ref_idx(&mut v, 0, 1);
  3. let (k, s) = ref_idx(&mut v, 0, 1); // second mutable borrow
  4. *i = 3;
  5. *j = 4;
  6. dbg!(v);

와 같은 코드를 작성하면 3번째 줄에서 2번째 mutable borrow가 일어나, 컴파일 에러가 납니다. 여기서, ijv에서 borrow 되었다는걸 borrow checker가 어떻게 아는지 궁금했습니다.

 

결론은, lifetime elision이 일어나기 때문입니다. parameter에서 reference가 하나인 경우, 모든 parameter와 return값의 lifetime이 '_로 설정되어서, ijv에서 borrow 되었다는걸 알 수 있습니다. 가령이면, 코드를 아래와 같이 작성하면 두 번째 mutable borrow를 할 수 있습니다. (물론, 이 코드는 unsafe합니다)

 

  1. fn ref_idx<'a, 'b> (v: &'a mut [i32], i: usize, j: usize) -> (&'b mut i32, &'b mut i32) {
  2.    assert!(i != j && i < v.len() && j < v.len());
  3.    let ptr = v.as_mut_ptr();
  4.    unsafe { (&mut *(ptr.add(i)), &mut *(ptr.add(j))) }
  5. }
  6.  
  7. // ...
  8.  
  9. let mut v = vec![1, 2];
  10. let (i, j) = ref_idx(&mut v, 0, 1);
  11. let (k, s) = ref_idx(&mut v, 0, 1); // unsafe! but compiled...
  12. *i = 3;
  13. *j = 4;
  14. dbg!(v);