2016-09-20 15 views
5

同じスライスの上部にスライスの終わりを書きたいと思います。スライスから同じスライスにデータを書き込むにはどうすればよいですか?

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]); 

私は(例えば、foo.as_ptr()を使用して)最大のパフォーマンスが可能たいHow to operate on 2 mutable slices of a Rust array

を見てきました。

+0

残念ながら、同様の機能は存在しないようですiteratorから 'IterMut'を補充する' collect'への呼び出しです。 – starblue

+1

も参照してください[スライスを慣用的にコピーする方法](http://stackoverflow.com/q/28219231/155423) – Shepmaster

答えて

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]); 
} 
7

一般的にスライス内のある範囲から別の範囲にデータをコピーするには(オーバーラップを許可する)、.split_at_mut()を使用することはできません。

私は.split_at_mut()を主に使用します。 (境界チェックが最適化されないと思われることはありますか?また、比較すると小さな効果である十分なデータをコピーしていますか?)

とにかく、これはどのようにラップできるかstd::ptr::copy -allowing 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

+0

Rustの初心者であれば、タイプTはドロップ特性を実装していますか? –

+1

'T:コピー 'とは、' T'がトリビュアコピー可能(バイト単位)であり、 'T'がデストラクタを持つことができないことを意味します。だから私たちはここに落ちることについて心配する必要はありません。 (この答えにはベクトルもなく、可変スライスだけです)。 – bluss

+0

ああ、コピー制約に気付かなかった。ありがとう。 –

2

あなたのタイプは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]); 
} 
+0

2つのスライスのサイズが異なる場合、機能はパニックになります。私の場合、同じスライスの先頭に5バイトの最後のバイトをコピーしたいのですが... – Kerollmops

+1

@Keroseneうん、同じ長さです "*。^_ ^ – Shepmaster

関連する問題