gpt4 book ai didi

pointers - 将 Option<&mut T> 转换为 *mut T

转载 作者:行者123 更新时间:2023-11-29 07:57:39 26 4
gpt4 key购买 nike

我正在围绕 C 库编写一个 Rust 包装器,同时我正在尝试利用 The Book 中提到的“可空指针优化” , 但我找不到转换 Option<&T> 的好方法至 *const TOption<&mut T>*mut T就像他们描述的那样。

我真正想要的是能够调用Some(&foo) as *const _ .不幸的是,这行不通,所以我能想到的下一个最好的事情是 Option<T> 上的特征。这让我可以调用 Some(&foo).as_ptr() .以下代码是该特征的工作定义和实现:

use std::ptr;

trait AsPtr<T> {
fn as_ptr(&self) -> *const T;
}

impl<'a, T> AsPtr<T> for Option<&'a T> {
fn as_ptr(&self) -> *const T {
match *self {
Some(val) => val as *const _,
None => ptr::null(),
}
}
}

现在我可以调用 Some(&foo).as_ptr()得到 *const _ , 我希望能够调用 Some(&mut foo).as_ptr()得到 *mut _ .以下是我为此所做的新特征:

trait AsMutPtr<T> {
fn as_mut_ptr(&self) -> *mut T;
}

impl<'a, T> AsMutPtr<T> for Option<&'a mut T> {
fn as_mut_ptr(&self) -> *mut T {
match *self {
Some(val) => val as *mut _,
None => ptr::null_mut(),
}
}
}

问题是,AsMutPtr特质不会编译。当我尝试时,出现以下错误:

error[E0507]: cannot move out of borrowed content
--> src/lib.rs:22:15
|
22 | match *self {
| ^^^^^
| |
| cannot move out of borrowed content
| help: consider removing the `*`: `self`
23 | Some(val) => val as *mut _,
| --- data moved here
|
note: move occurs because `val` has type `&mut T`, which does not implement the `Copy` trait
--> src/lib.rs:23:18
|
23 | Some(val) => val as *mut _,
| ^^^

我没有看到导致它失败的两个特征之间发生了什么变化——我不认为添加 mut会有很大的不同。我尝试添加 ref ,但这只会导致不同的错误,而且我不希望无论如何都需要它。

为什么 AsMutPtr 没有特质工作?

最佳答案

不幸的是,为 &mut T 编写了 trait impl而不是 &T 确实有很大的不同。 &mut T ,而不是 &T , 不是 Copy ,因此您不能直接从共享引用中提取它:

& &T      --->  &T
& &mut T -/-> &mut T

这是很自然的——否则可变引用的别名是可能的,这违反了 Rust 的借用规则。

你可能会问那个外层在哪里&来自。它实际上来自&selfas_mut_ptr()方法。如果您有对某物的不可变引用,即使该某物内部包含可变引用,您也无法使用它们来改变它们背后的数据。这也违反了借用语义。

不幸的是,如果没有不安全,我看不出有什么办法可以做到这一点。你需要有 &mut T “按值”以便将其转换为 *mut T ,但您无法通过共享引用“按值”获取它。因此,我建议您使用ptr::read() :

use std::ptr;

impl<'a, T> AsMutPtr<T> for Option<&'a mut T> {
fn as_mut_ptr(&self) -> *mut T {
match *self {
Some(ref val) => unsafe { ptr::read(val) as *mut _ },
None => ptr::null_mut(),
}
}
}

val这是 & &mut T因为ref模式中的限定符,因此 ptr::read(val)返回 &mut T , 别名可变引用。我认为如果它立即转换为原始指针并且不泄漏是可以的,但即使结果是原始指针,它仍然意味着您有两个别名可变指针。您应该非常小心地处理它们。

或者,您可以修改 AsMutPtr::as_mut_ptr()按值(value)消费其目标:

trait AsMutPtr<T> {
fn as_mut_ptr(self) -> *mut T;
}

impl<'a, T> AsMutPtr<T> for Option<&'a mut T> {
fn as_mut_ptr(self) -> *mut T {
match self {
Some(value) => value as *mut T,
None => ptr::null_mut()
}
}
}

但是,在这种情况下 Option<&mut T>将被 as_mut_ptr() 消耗.这可能不可行,例如,如果 Option<&mut T>存储在一个结构中。我不太确定是否可以通过 Option<&mut T> 以某种方式手动执行重新借用而不仅仅是 &mut T (不会自动触发);如果可能,则按值as_mut_ptr()可能是最好的整体解决方案。

关于pointers - 将 Option<&mut T> 转换为 *mut T,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35885670/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com