转换Option<& mut T>到* mut T [英] Convert Option<&mut T> to *mut T

查看:150
本文介绍了转换Option<& mut T>到* mut T的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在围绕C库编写一个Rust包装器,与此同时,我试图利用

I'm writing a Rust wrapper around a C library and while doing so I'm trying to take advantage of the "nullable pointer optimization" mentioned in The Book, but I can't find a good way to convert Option<&T> to *const T and Option<&mut T> to *mut T like what they're describing.

我真正想要的是能够打电话给Some(&foo) as *const _.不幸的是,这行不通,所以我能想到的第二件事是Option<T>上的一个特征,该特征使我能够调用Some(&foo).as_ptr().以下代码是该特征的有效定义和实现:

What I really want is to be able to call Some(&foo) as *const _. Unfortunately that doesn't work, so the next best thing I can think of is a trait on Option<T> that enables me to call Some(&foo).as_ptr(). The following code is a working definition and implementation for that trait:

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 _.以下是我为此做的新特征:

Now that I can call Some(&foo).as_ptr() to get a *const _, I want to be able to call Some(&mut foo).as_ptr() to get a *mut _. The following is the new trait I made to do this:

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特性无法编译.当我尝试时,出现以下错误:

The problem is, the AsMutPtr trait won't compile. When I try, I get the following error:

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,但这只会导致其他错误,而且我也不会期望这样做.

I don't see what changed between the two traits that causes it to fail — I didn't think adding mut would make that big a difference. I tried adding a ref, but that just causes a different error, and I wouldn't expect to need that anyway.

为什么AsMutPtr特性不起作用?

推荐答案

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

Unfortunately, writing the trait impl for &mut T instead of &T does make a big difference. &mut T, as opposed to &T, is not Copy, therefore you cannot extract it out of a shared reference directly:

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

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

This is fairly natural - otherwise aliasing of mutable references would be possible, which violates Rust borrowing rules.

您可能会问外层&的来源.它实际上来自as_mut_ptr()方法中的&self.如果您对某物的引用是不可变的,即使该内容中包含可变引用,您也将无法使用它们来对它们背后的数据进行突变.这也将违反借用语义.

You may ask where that outer & comes from. It actually comes from &self in as_mut_ptr() method. If you have an immutable reference to something, even if that something contains mutable references inside it, you won't be able to use them to mutate the data behind them. This also would be a violation of borrowing semantics.

不幸的是,如果没有不安全因素,我认为没有办法做到这一点.您必须具有&mut T按值"才能将其转换为*mut T,但不能通过共享引用将其按值"获取.因此,建议您使用ptr::read():

Unfortunately, I see no way to do this without unsafe. You need to have &mut T "by value" in order to cast it to *mut T, but you can't get it "by value" through a shared reference. Therefore, I suggest you to use 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(),
        }
    }
}

由于模式中的ref限定符,因此

val在这里是& &mut T,因此ptr::read(val)返回&mut T,别名是可变引用.我认为如果立即将其转换为原始指针并且不会泄漏出去是可以的,但是即使结果将是原始指针,也仍然意味着您拥有两个别名可变的指针.您应该非常小心对待他们.

val here is & &mut T because of ref qualifier in the pattern, therefore ptr::read(val) returns &mut T, aliasing the mutable reference. I think it is okay if it gets converted to a raw pointer immediately and does not leak out, but even though the result would be a raw pointer, it still means that you have two aliased mutable pointers. You should be very careful with what you do with them.

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

Alternatively, you may modify AsMutPtr::as_mut_ptr() to consume its target by 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()可能是最佳的整体解决方案.

However, in this case Option<&mut T> will be consumed by as_mut_ptr(). This may not be feasible if, for example, this Option<&mut T> is stored in a structure. I'm not really sure whether it is possible to somehow perform reborrowing manually with Option<&mut T> as opposed to just &mut T (it won't be triggered automatically); if it is possible, then by-value as_mut_ptr() is probably the best overall solution.

这篇关于转换Option&lt;&amp; mut T&gt;到* mut T的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆