簡體   English   中英

Rust split_at_mut 的實現

[英]Rust implementation of split_at_mut

我一直在閱讀 Rust Book,在關於 Unsafe Rust 的部分中,它展示了如何實現split_at_mut方法的簡單版本。 給定的實現是:

use std::slice;

fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = values.len();
    let ptr = values.as_mut_ptr();

    assert!(mid <= len);

    unsafe {
        (
            slice::from_raw_parts_mut(ptr, mid),
            slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}

但是,我想出了這個:

fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = values.len();
    assert!(mid <= len);

    let begin = &mut values[..mid] as *mut [i32];
    let end = &mut values[mid..] as *mut [i32];
    
    unsafe {
        (&mut *begin, &mut *end)
    }
}

這會產生(據我所知)相同的結果,但在我看來,它更易於閱讀。

那么是什么讓給定的解決方案比我的“更好”呢? 我的解決方案是否存在安全(或其他)問題? 給定的解決方案實際上更容易閱讀嗎? 是關於將此方法擴展到其他切片嗎? 是關於編碼風格和“良好實踐”嗎?

期待您的回答

這是我認為的原因(正如另一個答案所寫)Miri 拒絕您的代碼:

(
    slice::from_raw_parts_mut(ptr, mid),
    slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)

在這種情況下,您正在從來自單個&mut引用values的指針構造兩個非重疊的&mut引用。

let begin = &mut values[..mid] as *mut [i32];
let end = &mut values[mid..] as *mut [i32];
    
unsafe {
    (&mut *begin, &mut *end)
}

在這種情況下,您正在構建兩個臨時可變引用,它們都從values中借用(因此不能同時存在),然后從指針“復活”(不是技術術語)它們。

這是相同代碼的一個版本,它擴展了一些臨時變量和語法糖:

use std::ops::IndexMut;

let begin = {
    let v1 = &mut values;
    IndexMut::index_mut(v1, ..mid) as *mut [i32]
};
let end = {
    let v2 = &mut values;
    IndexMut::index_mut(v2, mid..) as *mut [i32]
};

unsafe { (&mut *begin, &mut *end) }

您的兩個指針beginend派生自v1v2 ,因此它們僅在v1v2存在時才有效,但v1v2相互沖突。

綜上所述,我不能確定允許這個程序是否可行,因為畢竟它不會創建任何實際的可變別名。 我絕對沒有受過 Miri 檢查的 Stacked Borrows model 理論基礎的教育。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM