回调到可变的 self

2023-12-07

有没有一种方法(在 Rust 中)可以将可变的借用自我发送到回调而不需要mem::replace我在以下 MWE 中使用的 hack?我正在使用 Rust stable (1.11.0)。

use std::mem;

trait Actable {
    fn act(&mut self);
}

// Not Cloneable
struct SelfCaller {
    message: String,
    callback: Box<FnMut(&mut SelfCaller)>,
    // other stuff
}

impl Actable for SelfCaller {
    fn act(&mut self) {
        fn noop(_: &mut SelfCaller) {}
        let mut callback = mem::replace(&mut self.callback, Box::new(noop));
        callback(self);
        mem::replace(&mut self.callback, callback);
    }
}

impl Drop for SelfCaller {
    fn drop(&mut self) {/* unimiportant to the story */}
}

fn main() {
    fn change(messenger: &mut SelfCaller) {
        messenger.message = "replaced message".to_owned();
    }

    let mut messenger = SelfCaller {
        message: "initial message".to_owned(),
        callback: Box::new(change),
    };

    messenger.act();

    println!("{}", &messenger.message);
}

Play


不,没有办法,因为这样做不安全。这是一个演示原因的示例(需要夜间编译器)。

#![feature(fn_traits)]
#![feature(unboxed_closures)]

use std::mem;

trait Actable {
    fn act(&mut self);
}

struct SelfCaller {
    message: String,
    callback: Box<FnMut(&mut SelfCaller)>,
}

impl Actable for SelfCaller {
    fn act(&mut self) {
        let mut callback: &mut Box<FnMut(&mut SelfCaller)> = unsafe { mem::transmute(&mut self.callback) };
        println!("calling callback");
        callback(self);
        println!("called callback");
    }
}

struct Callback;

impl Drop for Callback {
    fn drop(&mut self) {
        println!("Callback dropped!");
    }
}

impl<'a> FnOnce<(&'a mut SelfCaller,)> for Callback {
    type Output = ();

    extern "rust-call" fn call_once(mut self, args: (&mut SelfCaller,)) {
        self.call_mut(args)
    }
}

impl<'a> FnMut<(&'a mut SelfCaller,)> for Callback {
    extern "rust-call" fn call_mut(&mut self, (messenger,): (&mut SelfCaller,)) {
        println!("changing callback");
        messenger.callback = Box::new(|messenger| {});
        println!("changed callback");
        messenger.message = "replaced message".to_owned();
    }
}

fn main() {
    let change = Callback;

    let mut messenger = SelfCaller {
        message: "initial message".to_owned(),
        callback: Box::new(change),
    };

    messenger.act();

    println!("{}", &messenger.message);
}

该程序的输出是:

calling callback
changing callback
Callback dropped!
changed callback
called callback
replaced message

好吧,那到底是怎么回事?首先,我写了实现act for SelfCaller以这样的方式我can调用回调而不mem::replace, using mem::transmute让编译器生成一个新的生命周期,与self.

然后,我编写了一个回调(使用结构Callback,因为我需要一个同时实现两者的类型FnMut and Drop来证明问题),这会改变SelfCaller通过改变其callback成员。这有以下效果删除之前的回调,这是当前正在执行的回调!如果Callback包含数据成员,尝试读取它们会导致未定义的行为,因为它们现在位于已释放的内存中(我们删除了整个Box).


顺便说一下,在你的代码中使用mem::replace,回调不能更改回调,因为您在回调调用结束后恢复回调。

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

回调到可变的 self 的相关文章

随机推荐

  • 从浏览器执行 HTTP PUT

    我想知道最终的 答案是什么 除了从浏览器进行 POST GET 之外 如何做其他事情 无论是 HTML 表单还是 Ajax 因为我听到关于哪些浏览器允许什么 特别是在 ajax 方面 的混合报告 当以 RESTful 风格构建后端时 最好使
  • Java序列化

    我现在正在学习如何使用进行序列化Java语言 我已经阅读了一些有关该主题的帖子和文档 并且尝试做一个简单的示例 如下 public class SterializeObject implements java io Serializable
  • 获取一系列待处理的承诺

    var arr 1 2 3 4 5 6 67 8 10 function f1 return arr map function member console log member return Promise resolve member
  • Angular 6 在两个不相关的组件之间传递数据

    我有课程详细信息组件 其中包含来自后端应用程序的数据 名为课程 我想将该数据传递给与该组件无关的另一个组件 课程播放 我想在这两个组件中显示从后端获得的相同数据 这是相关文件 应用程序路由模块 import NgModule from an
  • 批处理文件中的字符串替换

    我们可以使用以下命令替换批处理文件中的字符串 set str jump over the chair set str str chair table 这些行工作正常 并将字符串 jump over the chair 更改为 jump ov
  • Google 地图 API 错误:此 API 密钥无权使用此服务或 API。地点 API 错误:ApiTargetBlockedMapError

    我开始从我使用的 CMS 内的 Google 地图小部件收到此错误 This API key is not authorized to use this service or API Places API error ApiTargetBl
  • 在 Python 中生成 CSR

    我正在尝试在 Python 中生成 CSR 而不使用 OpenSSL 如果有人能指出正确的方向 我将非常感激 我假设你不想使用命令行 openssl 本身 Python 库就可以了 这是我编写的用于创建 CSR 的辅助函数 它从生成的密钥对
  • ConvertTimeFromUTC,处理澳大利亚夏令时

    我有以下代码 我有一位位于澳大利亚堪培拉的客户 它们通常是 UTC 10 但现在处于 DST 所以是 UTC 11 奇怪的是 当我运行此代码时 它没有考虑 DST 我认为 ConvertTimeFromUTC 可以处理 DST 我正在路过E
  • 使用 Xcode、Swift3 的 iOS Rich Push 通知但无法获取图像

    我正在尝试使用 Xcode Swift3 创建 iOS 丰富推送通知 我已经使用 php 的curl 命令确定推送通知 主题 正文 但我无法创建引用的丰富推送通知在本文件中 我添加了通知服务扩展 如下所示 File New Target N
  • JTextArea 中的行

    有没有可靠的方法来计算 JTextArea 中字符串如何划分为行 我有一个固定宽度的 JTextArea 当它被填充时 会添加一个新行并垂直扩展 现在 我需要确切地知道哪些字符位于哪一行 我可以使用字体规格来添加单个字符宽度 但我不知道这是
  • 如何对表中特定数量的行进行着色?

    如何仅对特定数量的行进行着色 这里我的显示屏只有前 7 行是白色的 其余的是灰色的 我想要 7 条白色线 7 条灰色线 7 条白色线 7 条灰色线等等 你可以尝试这样的事情 table gt span height 20px width 2
  • 将 php 变量添加到 css 语句中!

    我想在我的 css 样式声明中包含以下内容 是否可以
  • 如果表2中不存在,如何插入到表1中?

    我是mysql新手 如果 table2 中不存在记录 则将记录插入到 table1 时出现问题 我有 2 个表 table1 和 table2 其形式为 table1 dep id start stop modified deleted 1
  • 是否可以在Python中创建特定目录的快捷方式?

    我查了一下 inetrnet 但没有发现任何相关内容 所以我在这里问 是否可以使用 python 创建文件的快捷方式并将其放入我选择的特定目录中 例如 我在 C 中有一个名为 EXAMPLE 的文件夹 我想自动创建谷歌浏览器的快捷方式并将其
  • 我可以序列化 ruby​​ Digest::SHA1 实例对象吗?

    大家好 我正在 ruby sinatra 中重新实现现有的自定义文件上传服务 并使用 redis 作为后备存储 客户 计算 SHA1 哈希并启动上传 上传最多 64K 块直至完成 服务器 将块附加到文件 计算完整文件的 SHA1 哈希值以验
  • 在 Ansible 中,如何将活动角色的变量组合到一个数组中?

    看着 在 Ansible 中 如何将不同文件中的变量合并到一个数组中 答案之一建议使用包含变量要将多个来源的变量放入一个数组中 这是almost我需要什么 但不完全是 我正在设置 cloudfront logging 它需要 a 中的项目a
  • Qt 使应用程序始终位于 Weston/Wayland 平台之上

    我想在 Wayland Weston 桌面系统中安排两个应用程序的焦点 两个应用是 用 Qt QML 编写 全屏 使用 Wayland 客户端 API OpenGL 编写 全屏 我想让 App 1 始终位于顶部 App 2 始终位于底部 即
  • 使用 ElementTree 从混合元素 xml 标签中获取文本

    我正在使用 ElementTree 来解析我拥有的 XML 文档 我从以下位置获取文本u标签 其中一些包含混合内容 我需要过滤掉或保留为文本 我有两个例子 u u
  • 删除 id=".xxx" 的 div 或 span

    我无法删除 id 带有句点或星号的 div div div div div 我有 jquery 代码 它删除了 div div 但不是上面的 不是在寻找 jQuery 代码 但它需要正斜杠吗 来自 anurag 的请求 JavaScript
  • 回调到可变的 self

    有没有一种方法 在 Rust 中 可以将可变的借用自我发送到回调而不需要mem replace我在以下 MWE 中使用的 hack 我正在使用 Rust stable 1 11 0 use std mem trait Actable fn