原文链接:https://doc.rust-lang.org/nomicon/borrow-splitting.html

分解借用

可变引用的Mutex属性在处理复合类型时能力非常有限。借用检查器只能理解一些简单的东西,而且极易失败。他对结构体还算是充分了解,知道结构体的成员可能被分别借用。所以这段代码现在可以正常工作:

  1. struct Foo {
  2. a: i32,
  3. b: i32,
  4. c: i32,
  5. }
  6. let mut x = Foo {a: 0, b: 0, c: 0};
  7. let a = &mut x.a;
  8. let b = &mut x.b;
  9. let c = &x.c;
  10. *b += 1;
  11. let c2 = &x.c;
  12. *a += 10;
  13. println!("{} {} {} {}", a, b, c, c2);

但是,借用检查器对于数组和slice的理解却是一团浆糊,所以这段代码无法通过检查:

  1. let mut x = [1, 2, 3];
  2. let a = &mut x[0];
  3. let b = &mut x[1];
  4. println!("{} {}", a, b);
  1. <anon>:4:14: 4:18 error: cannot borrow `x[..]` as mutable more than once at a time
  2. <anon>:4 let b = &mut x[1];
  3. ^~~~
  4. <anon>:3:14: 3:18 note: previous borrow of `x[..]` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x[..]` until the borrow ends
  5. <anon>:3 let a = &mut x[0];
  6. ^~~~
  7. <anon>:6:2: 6:2 note: previous borrow ends here
  8. <anon>:1 fn main() {
  9. <anon>:2 let mut x = [1, 2, 3];
  10. <anon>:3 let a = &mut x[0];
  11. <anon>:4 let b = &mut x[1];
  12. <anon>:5 println!("{} {}", a, b);
  13. <anon>:6 }
  14. ^
  15. error: aborting due to 2 previous errors

借用检查器连这个简单的场景都理解不了,那它更不可能理解一些通用容器类型了,比如说树,尤其是出现不同的键对应相同的值的时候。

为了能“教育”借用检查器我们的所作所为是正确的,我们还是要使用非安全代码。比如,可变slice暴露了一个split_at_mut的方法,它接收一个slice然后返回两个可变slice。一个包括索引值左边所有的值,另一个包含右边所有的值。我们知道这个方法是安全的,因为两个slice没有重叠部分,也就不会出现别名问题。但是它的实现还是要涉及到非安全的内容:

  1. fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
  2. let len = self.len();
  3. let ptr = self.as_mut_ptr();
  4. assert!(mid <= len);
  5. unsafe {
  6. (from_raw_parts_mut(ptr, mid)),
  7. from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
  8. }
  9. }

这有一点难懂。为了避免两个&mut指向相同的值,我们通过裸指针显式创建了两个全新的slice。

不过迭代器产生可变引用的方法更加难懂。迭代器trait的定义如下:

  1. trait Iterator {
  2. typr Item;
  3. fn next(&mut self) -> Option<Self::Item>;
  4. }

这份定义里,Self::Itemslef没有直接关系。也就是说我们可以连续调用next很多次,并且同时保存着所有的结果。对于值的迭代器这么做完全可以,完全符合语义。对于共享引用这么做也没什么问题,因为允许任意过个共享引用指向同一个值(当然迭代器本身需要是独立于被共享内容的对象)。

但是可变引用就麻烦了。乍一看,可变引用完全不适用这个API,因为那会产生多个指向相同对象的可变引用。

可实际上它能够正常工作,这是因为迭代器是一个一次性对象。IterMut生成的东西最多只会生成一次,所以实际上我们没有生成多个指向相同数据的可变指针。

更不可思议的是,可变迭代器对于许多类型的实现甚至不需要非安全代码!

例如,下面是单向列表的代码:

  1. type Link<T> = Option<Box<Node<T>>>;
  2. struct Node<T> {
  3. elem: T,
  4. next: Link<T>,
  5. }
  6. pub struct LinkedList<T> {
  7. head: Link<T>,
  8. }
  9. pub struct IterMut<'a, T: 'a>(Option<&'a mut Node<T>>);
  10. impl<T> LinkedList<T> {
  11. fn iter_mut(&mut self) -> IterMut<T> {
  12. IterMut(self.head.as_mut().map(|node| &mut **node))
  13. }
  14. }
  15. impl<'a, T> Iterator for IterMut<'a, T> {
  16. type Item = &'a mut T;
  17. fn next(&mut self) -> Option<Self::Item> {
  18. self.0.take().map(|node| {
  19. self.0 = node.next.as_mut().map(|node| &mut **node);
  20. &mut node.elem
  21. })
  22. }
  23. }

这是可变slice:

  1. use std::mem;
  2. pub struct IterMut<'a, T: 'a>(&'a mut[T]);
  3. impl<'a, T> Iterator for IterMut<'a, T> {
  4. type Item = &'a mut T;
  5. fn next(&mut self) -> Option<Self::Item> {
  6. let slice = mem::replace(&mut self.0, &mut []);
  7. if slice.is_empty() { return None; }
  8. let (l, r) = slice.split_at_mut(1);
  9. self.0 = r;
  10. l.get_mut(0)
  11. }
  12. }
  13. impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
  14. fn next_back(&mut self) -> Option<Self::Item> {
  15. let slice = mem::replace(&mut self.0, &mut []);
  16. if slice.is_empty() { return None; }
  17. let new_len = slice.len() - 1;
  18. let (l, r) = slice.split_at_mut(new_len);
  19. self.0 = l;
  20. r.get_mut(0)
  21. }
  22. }

还有二叉树:

  1. use std::collections::VecDeque;
  2. type Link<T> = Option<Box<Node<T>>>;
  3. struct Node<T> {
  4. elem: T,
  5. left: Link<T>,
  6. right: Link<T>,
  7. }
  8. pub struct Tree<T> {
  9. root: Link<T>,
  10. }
  11. struct NodeIterMut<'a, T: 'a> {
  12. elem: Option<&'a mut T>,
  13. left: Option<&'a mut Node<T>>,
  14. right: Option<&'a mut Node<T>>,
  15. }
  16. enum State<'a, T: 'a> {
  17. Elem(&'a mut T),
  18. Node(&'a mut Node<T>),
  19. }
  20. pub struct IterMut<'a, T: 'a>(VecDeque<NodeIterMut<'a, T>>);
  21. impl<T> Tree<T> {
  22. pub fn iter_mut(&mut self) -> IterMut<T> {
  23. let mut deque = VecDeque::new();
  24. self.root.as_mut().map(|root| deque.push_front(root.iter_mut()));
  25. IterMut(deque)
  26. }
  27. }
  28. impl<T> Node<T> {
  29. pub fn iter_mut(&mut self) -> NodeIterMut<T> {
  30. NodeIterMut {
  31. elem: Some(&mut self.elem),
  32. left: self.left.as_mut().map(|node| &mut **node),
  33. right: self.right.as_mut().map(|node| &mut **node),
  34. }
  35. }
  36. }
  37. impl<'a, T> Iterator for NodeIterMut<'a, T> {
  38. type Item = State<'a, T>;
  39. fn next(&mut self) -> Option<Self::Item> {
  40. match self.left.take() {
  41. Some(node) => Some(State::Node(node)),
  42. None => match self.elem.take() {
  43. Some(elem) => Some(State::Elem(elem)),
  44. None => match self.right.take() {
  45. Some(node) => Some(State::Node(node)),
  46. None => None,
  47. }
  48. }
  49. }
  50. }
  51. }
  52. impl<'a, T> DoubleEndedIterator for NodeIterMut<'a, T> {
  53. fn next_back(&mut self) -> Option<Self::Item> {
  54. match self.right.take() {
  55. Some(node) => Some(State::Node(node)),
  56. None => match self.elem.take() {
  57. Some(elem) => Some(State::Elem(elem)),
  58. None => match self.left.take() {
  59. Some(node) => Some(State::Node(node)),
  60. None => None,
  61. }
  62. }
  63. }
  64. }
  65. }
  66. impl<'a, T> Iterator for IterMut<'a, T> {
  67. type Item = &'a mut T;
  68. fn next(&mut self) -> Option<Self::Item> {
  69. loop {
  70. match self.0.front_mut().and_then(|node_it| node_it.next()) {
  71. Some(State::Elem(elem)) => return Some(elem),
  72. Some(State::Node(node)) => self.0.push_front(node.iter_mut()),
  73. None => if let None = self.0.pop_front() { return None },
  74. }
  75. }
  76. }
  77. }
  78. impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
  79. fn next_back(&mut self) -> Option<Self::Item> {
  80. loop {
  81. match self.0.back_mut().and_then(|node_it| node_it.next_back()) {
  82. Some(State::Elem(elem)) => return Some(elem),
  83. Some(State::Node(node)) => self.0.push_back(node.iter_mut()),
  84. None => if let None = self.0.pop_back() { return None },
  85. }
  86. }
  87. }
  88. }

所有这些都是完全安全而且能稳定运行的!这已经超出了我们之前看过的简单结构体的例子:Rust能够理解你把一个可变引用安全地分解为多个部分。接下来我们可以通过Option永久地访问这个引用(或者像对于slice那样,替换为一个空的slice)。