【问题标题】:How can I write data from a slice to the same slice?如何将切片中的数据写入同一个切片?
【发布时间】:2017-01-28 23:10:22
【问题描述】:

我想将切片的结尾写入同一切片的顶部。

let mut foo = [1, 2, 3, 4, 5];

foo[..2].copy_from_slice(&[4..]); // error: multiple references to same data (mut and not)

assert!(foo, [4, 5, 3, 4, 5]);

我见过How to operate on 2 mutable slices of a Rust array

我希望尽可能发挥最大性能(例如,通过使用 foo.as_ptr())。

【问题讨论】:

标签: rust slice


【解决方案1】:

Rust 1.37 (2019-08-15) 添加了库函数 slice::copy_within,这正是您想要的:

let mut foo = [1, 2, 3, 4, 5];

foo.copy_within(3 .. 5, 0);  // <-- THIS

assert_eq!(foo, [4, 5, 3, 4, 5]);

【讨论】:

    【解决方案2】:

    我找到了一种更好的方法来做我想做的事:

    fn main() {
        let mut v = [1, 2, 3, 4, 5, 6];
    
        // scoped to restrict the lifetime of the borrows
        {
            let (left, right) = v.split_at_mut(3);
            assert!(left == [1, 2, 3]);
            assert!(right == [4, 5, 6]);
            for (l, r) in left.iter_mut().zip(right) {
                *l = *r;
            }
        }
    
        assert!(v == [4, 5, 6, 4, 5, 6]);
    }
    

    【讨论】:

      【解决方案3】:

      如果您的类型实现 Copy 并且子切片不重叠:

      fn main() {
          let mut v = [1, 2, 3, 4, 5, 6];
      
          {
              let (left, right) = v.split_at_mut(3);
              // Perform further work to ensure slices are the same length, as needed
              left.copy_from_slice(right);
          }
      
          assert!(v == [4, 5, 6, 4, 5, 6]);
      }
      

      【讨论】:

      • 如果两个切片的大小不同,函数会出现恐慌,在我的情况下,我想复制同一切片前面的最后 5 个字节...
      • @Kerosene 是的,这就是为什么我放了评论“确保切片长度相同”。 ^_^
      【解决方案4】:

      一般来说,要将切片中的一个范围内的数据复制到另一个范围(允许重叠),我们甚至不能使用.split_at_mut()

      我会主要使用.split_at_mut()。 (有没有什么让你认为边界检查不会被优化出来?另外,你复制的数据是否足够多,相比之下它的影响很小?)

      无论如何,这就是您可以将std::ptr::copy(允许重叠的复制,又名 memmove)包装在保险箱或 unsafe 函数中的方式。

      use std::ptr::copy;
      use std::ops::Range;
      
      /// Copy the range `data[from]` onto the index `to` and following
      ///
      /// **Panics** if `from` or `to` is out of bounds
      pub fn move_memory<T: Copy>(data: &mut [T], from: Range<usize>, to: usize) {
          assert!(from.start <= from.end);
          assert!(from.end <= data.len());
          assert!(to <= data.len() - (from.end - from.start));
          unsafe {
              move_memory_unchecked(data, from, to);
          }
      }
      
      pub unsafe fn move_memory_unchecked<T: Copy>(data: &mut [T], from: Range<usize>, to: usize) {
          debug_assert!(from.start <= from.end);
          debug_assert!(from.end <= data.len());
          debug_assert!(to <= data.len() - (from.end - from.start));
          let ptr = data.as_mut_ptr();
          copy(ptr.offset(from.start as isize),
               ptr.offset(to as isize),
               from.end - from.start)
      }
      
      fn main() {
          let mut data = [0, 1, 2, 3, 4, 5, 6, 7];
          move_memory(&mut data, 2..6, 0);
          println!("{:?}", data);
          move_memory(&mut data, 0..3, 5);
          println!("{:?}", data);
      }
      

      Playground link

      【讨论】:

      • 作为 Rust 的初学者,请问当类型 T 实现 Drop Trait 时,向量元素 drop 在这种情况下对于类型 T 将如何工作?
      • 当然。 T: Copy 意味着 T 可以简单地复制(逐字节),这也意味着 T 不能有析构函数。所以我们不必担心掉到这里。 (这个答案中也没有向量,只是一个可变切片)。
      • 啊,是的,没有注意到 Copy 约束。谢谢。
      猜你喜欢
      • 2019-10-29
      • 2018-05-30
      • 2017-12-13
      • 2022-08-09
      • 2021-02-11
      • 1970-01-01
      • 2018-04-22
      • 1970-01-01
      • 2015-07-03
      相关资源
      最近更新 更多