首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Option<&mut T>转换为*mut T

将Option<&mut T>转换为*mut T
EN

Stack Overflow用户
提问于 2016-03-09 07:39:46
回答 4查看 2K关注 0票数 6

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

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

代码语言:javascript
复制
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 _。以下是我做这件事的新特点:

代码语言:javascript
复制
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特性无法编译。当我尝试时,我会得到以下错误:

代码语言:javascript
复制
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特性不起作用?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-03-09 10:01:26

不幸的是,为&mut T而不是&T编写这个特性确实带来了很大的不同。与&mut T相比,&T不是Copy,因此不能直接从共享引用中提取它:

代码语言:javascript
复制
& &T      --->  &T
& &mut T  -/->  &mut T

这是相当自然的--否则就有可能对可变引用进行别名,这违反了锈蚀借用规则。

您可能会问,外部&来自何处。它实际上来自于&self中的as_mut_ptr()方法。如果您对某物具有不可变的引用,即使其中包含可变的引用,您也无法使用它们来修改它们后面的数据。这也将违反借用语义学。

不幸的是,我认为在没有不安全的情况下无法做到这一点。您需要“按值”将&mut T转换为*mut T,但不能通过共享引用“按值”获得它。因此,我建议您使用ptr::read()

代码语言:javascript
复制
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()以按值使用它的目标:

代码语言:javascript
复制
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()可能是最好的整体解决方案。

票数 5
EN

Stack Overflow用户

发布于 2016-03-10 22:02:06

问题是,您正在从&mut中读取&,但是&muts不是Copy,所以必须移动--而且不能从const引用中移出。这实际上解释了弗拉基米尔·马特维耶夫( Vladimir )从更基本的属性角度对&&mut → &的洞察力。

这其实是比较简单的解决办法。如果您可以读取*const _,则可以读取*mut _。这两者是相同的类型,除了一个标志,上面写着“小心,这是共享的”。因为不管是哪种方式,取消都是不安全的,因此实际上没有理由阻止您在两者之间穿插。

所以你真的可以

代码语言:javascript
复制
match *self {
    Some(ref val) => val as *const _ as *mut _,
    None => ptr::null_mut(),
}

读取不可变引用,使其成为不可变指针,然后使其成为可变指针。另外,这一切都是通过安全锈蚀完成的,所以我们知道我们没有违反任何别名规则。

也就是说,在*mut引用消失之前实际使用&mut指针可能是个坏主意。我会对此犹豫不决,并试图重新考虑您的包装,以更安全的东西。

票数 2
EN

Stack Overflow用户

发布于 2016-03-09 08:11:22

这能满足你的期望吗?

代码语言:javascript
复制
trait AsMutPtr<T> {
    fn as_mut_ptr(self) -> *mut T;
}

impl<T> AsMutPtr<T> for Option<*mut T> {
    fn as_mut_ptr(self) -> *mut T {
        match self {
            Some(val) => val as *mut _,
            None => ptr::null_mut(),
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35885670

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档