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

2024-05-29

我正在围绕 C 库编写一个 Rust 包装器,同时我试图利用中提到的“可空指针优化”The Book https://doc.rust-lang.org/1.30.0/book/first-edition/ffi.html#the-nullable-pointer-optimization,但我找不到好的转换方法Option<&T> to *const T and Option<&mut T> to *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特质工作?


不幸的是,编写trait impl为&mut T代替&T does有很大的不同。&mut T,相对于&T, 不是Copy,因此您不能直接从共享引用中提取它:

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

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

你可能会问那个外层在哪里&来自。它实际上来自&self in as_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()按价值消耗其目标:

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()可能是最好的整体解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 Option<&mut T> 转换为 *mut T 的相关文章

随机推荐

  • 将变量从调用它的父页面传递给 Vue 组件

    我有一个简单的表格 显示了我的所有数据 主文件 php table class table table bordered table hover thead tr th Job Name th th Job Description th t
  • 线程安全的有限大小队列,不使用锁

    我正在尝试编写一个主题队列 但遇到死锁和其他多线程问题 我想用Interlocked CompareExchange避免lock用法 但这段代码并没有按预期工作 它只是擦除整个队列 我在这里做错了什么 public class FixedS
  • JbdcTemplate - 带有动态 SQL 查询的PreparedStatements

    I know jdbcTemplate可以用来创建PreparedStatements如果你这样设置 i e private JdbcTemplate jdbcTemplate String sqlQuery Select from tab
  • html 表:thead 与 th

    它看起来像 根据示例这一页 http www w3 org TR html4 struct tables html无论如何 如果您使用THEAD 则不需要使用TH 真的吗 如果是这样 THEAD 与 TH 相比有何优点 缺点 The the
  • 从 Web 打印“原始文本”(ZPL)

    我们有很多旧的 ZPL 标签 我们希望能够从网络客户端打印它们 打印机连接到客户端而不是服务器 我们有一些想法 从 Silverlight 打印 不可行 似乎无法在不调用 COM 对象的情况下从 NET 打印 原始 到 Zebra 而这在普
  • 获取给定日期的周数

    例子 DD MM YYYY 1 1 2009 should give 1 31 1 2009 should give 5 1 2 2009 should also give 5 Format 1 2 2009 ww 回报6 那么 怎样才能得
  • SendGrid事件通知认证

    我已经为 sendgrid 设置了一个端点来发送事件通知 但是 服务器设置了基本身份验证 并且事件不会通过 因为它们未经身份验证 如何通过 SendGrid 或将 SendGrid 列入白名单来验证这些事件 Webhook 设置 HTTP
  • 为什么 SSRS 报表从 SQL Server Reporting Services 运行时生成的数据与使用“预览”选项卡运行时生成的数据不同?

    我有一个运行我想要的数据的报表 从 预览 选项卡 即 或者在 VS 2010 中使用 F5 运行时 但是当我将报表 rdl 文件 上传到 SQL Server Reporting Services 并运行更新后的报表时从那里报告 它仍然显示
  • AWS CloudWatchLog 限制

    我正在尝试找到集中式解决方案来将我的应用程序日志记录从数据库 RDS 中移出 我本想使用 CloudWatchLog 但注意到 PutLogEvents 请求有限制 PutLogEvents 请求的最大速率为每秒 5 个请求 每个日志流 即
  • 查找和替换正则表达式问题

    感谢这里对我其他问题的所有大力帮助 我开始掌握正则表达式 但我仍然对这个一无所知 我的代码是 StreamReader reader new StreamReader fDialog FileName ToString string con
  • iphone相当于android打开其他应用程序的意图

    是否有像 iphone 中可用的 android 意图功能 Android 使用意图从调用应用程序打开其他应用程序 以使用其他应用程序已实现的功能 我在某处读到 iphone 有 url 方案 但找不到更多信息 thanks 尝试查看以下答
  • 尝试设置 requestPointerLock() 时似乎出现问题

    我的代码似乎有问题 但我不知道是什么 我正在尝试调用pointerlockchange api 来禁用指针并使用鼠标作为fps 控制器 问题是总是指针锁错误被触发 我得到一个设置指针锁定时出错 信息 内部调用了该函数 文档 准备好 这是代码
  • LinearLayout onclick 在 TranslateAnimation 后不翻译

    这是我的问题 我有一个 LinearLayout 它的 clickable true 为 onTouch 事件 以便当 LinearLayout 被触摸时 它会滑动 屏幕上 这是可行的 但是当 onTouch 事件发生后 从新位置解雇没有任
  • 如何获取已退出的 docker 容器的数字退出状态?

    当容器退出时 docker ps a显示其退出代码 滚动 docker run ubuntu bash c exit 1 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c2c76
  • R:使用管道将单个参数传递到函数中的多个位置

    我试图专门使用管道来重写以下代码 使用babynames包中的babynames数据 library babynames library dplyr myDF lt babynames gt group by year gt summari
  • Wordnet sqlite 同义词和示例

    我正在尝试获取给定 wordid 的同义词和示例列表 经过大量的试验和错误 我可以获得所有同义词集的样本 但不是实际的同义词 这是我的查询 它给出了以下结果 select senses wordid senses synsetid sens
  • 服务器发现和监控引擎已弃用

    我在 Node js 应用程序中使用 Mongoose 这是我的配置 mongoose connect process env MONGO URI useNewUrlParser true useUnifiedTopology true u
  • Python:将 xml 文件转换为图像

    我希望使用 python 脚本将 xml 文件转换为图像 最好是 png 文件 我没有从我的在线研究中找到太多信息 我正在尝试使用 PIL 从这个帖子 https stackoverflow com questions 5741803 co
  • 数组反序列化的Gson数组

    我有以下 JSON 结构 id 1 subcategories id 2 subcategories id 3 subcategories id 4 subcategories id 5 subcategories 类别的模型类 为简单起见
  • 将 Option<&mut T> 转换为 *mut T

    我正在围绕 C 库编写一个 Rust 包装器 同时我试图利用中提到的 可空指针优化 The Book https doc rust lang org 1 30 0 book first edition ffi html the nullab