简体   繁体   English

Rust split_at_mut 的实现

[英]Rust implementation of split_at_mut

I've been reading the Rust Book, and in the section about Unsafe Rust, it shows how to implement a simple version of the split_at_mut method.我一直在阅读 Rust Book,在关于 Unsafe Rust 的部分中,它展示了如何实现split_at_mut方法的简单版本。 The given implementation is:给定的实现是:

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),
        )
    }
}

However, I came up with this:但是,我想出了这个:

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

which produces (as far as I know) the same result, but is, in my opinion, easier to read.这会产生(据我所知)相同的结果,但在我看来,它更易于阅读。

So what makes the given solution "better" than mine?那么是什么让给定的解决方案比我的“更好”呢? Does my solution has a safety (or other) issue?我的解决方案是否存在安全(或其他)问题? Is the given solution, in fact, easier to read?给定的解决方案实际上更容易阅读吗? Is it about extending this method over other slices?是关于将此方法扩展到其他切片吗? Is it about coding style and "good practice"?是关于编码风格和“良好实践”吗?

Looking forward to your answers期待您的回答

Here is what I think is going on with why (as another answer wrote) Miri rejects your code:这是我认为的原因(正如另一个答案所写)Miri 拒绝您的代码:

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

In this case, you are constructing two non-overlapping &mut references from a pointer that came from the single &mut reference values .在这种情况下,您正在从来自单个&mut引用values的指针构造两个非重叠的&mut引用。

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

In this case, you are constructing two temporary mutable references, both of which borrow from values (and thus cannot be live at the same time), then “resurrecting” (not a technical term) them from pointers.在这种情况下,您正在构建两个临时可变引用,它们都从values中借用(因此不能同时存在),然后从指针“复活”(不是技术术语)它们。

Here is a version of the same code which expands some temporaries and syntax sugar:这是相同代码的一个版本,它扩展了一些临时变量和语法糖:

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

Your two pointers begin and end are derived from v1 and v2 , and therefore they are only valid to use as long as v1 and v2 are, but v1 and v2 conflict with each other.您的两个指针beginend派生自v1v2 ,因此它们仅在v1v2存在时才有效,但v1v2相互冲突。

All that said, I can't say for sure whether it wouldn't be okay to allow this program since, after all, it does not create any actual mutable aliasing.综上所述,我不能确定允许这个程序是否可行,因为毕竟它不会创建任何实际的可变别名。 I am definitely not educated in the theoretical basis of the Stacked Borrows model that Miri checks.我绝对没有受过 Miri 检查的 Stacked Borrows model 理论基础的教育。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM