【问题标题】:Is it possible to associate memory from one struct with another in Rust?是否可以在 Rust 中将一个结构的内存与另一个结构相关联?
【发布时间】:2019-07-25 05:00:59
【问题描述】:

我知道,在 Rust 中,编译器不保证您按照声明它们的顺序获取结构数据,以节省内存(我也相信一些 C 代码优化器也在做同样的事情)。假设现在我有一个二叉树并且想将它转换为一个双链表。在 C 中我会声明两个结构:

typedef struct tree{
    void* left_child;
    void* right_child;
    void* data;
}tree_t;

对于树,并且:

typedef struct list{
    void* before;
    void* after;
    void* data;
}list_t;

对于链表。如果我现在想将树转换为列表,我可以就地执行此操作,只需将树的内存与列表结构相关联并更改指针:

tree_t mytree;
/*fill tree*/
list_t *list_p;
list_p = (list_t)&mytree;
/*change pointers accordingly*/

但是我怎么能在 Rust 中做这样的事情呢?甚至可以不使用unsafe 代码吗? 到现在我有我的树了:

struct TreeNode<'a, T> {
    left_child: BinaryTreeLink<'a, T>,
    right_child: BinaryTreeLink<'a, T>,
    data : &'a T,
}

type BinaryTreeLink<'a, T> = Option<Box<TreeNode<'a, T>>>;

列表将是:

struct ListNode<'a, T> {
    before: ListLink<'a, T>,
    after: ListLink<'a, T>,
    data : &'a T,
}

type ListLink<'a, T> = Option<Box<ListNode<'a, T>>>;

但是我现在怎样才能有效地转换它们呢?

【问题讨论】:

  • 听起来像是 mem::transmute 的工作,但正如您所怀疑的那样,这非常不安全。
  • 我对这种模式并不十分熟悉,能否请您扩展一下您想要实现的目标? std::mem::transmute 会做你想要做的事情,但它是不安全的,所以也许提供你想要做的事情的解释可能会揭示一个更好的实现方法。
  • 我正在尝试将二叉树转换为链表,这意味着不消耗额外的内存来构建链表。

标签: linked-list rust binary-tree type-punning


【解决方案1】:

但是我怎样才能在 Rust 中做这样的事情呢?甚至可以不使用不安全的代码吗?直到现在我有我的树

直接做同样的事情,你需要使用不安全的代码。函数std::mem::transmute 完全符合您的要求。问题是 Rust 中结构的布局是没有保证的,所以以下通常是 Undefined Behaviour:

use std::mem;
let list_link: Option<Box<ListNode<_>>> = unsafe { mem::transmute(tree_node) };

但是,您可以通过使用C 表示强制结构的布局可预测来使其安全:

#[repr(C)]
struct TreeNode<'a, T> {
    left_child: BinaryTreeLink<'a, T>,
    right_child: BinaryTreeLink<'a, T>,
    data : &'a T,
}

#[repr(C)]
struct ListNode<'a, T> {
    before: ListLink<'a, T>,
    after: ListLink<'a, T>,
    data : &'a T,
}

您还需要将#[repr(C)] 应用于内部类型的定义ListLinkBinaryTreeLink


但是完全避免不安全的代码呢?如果您编写使用原始数据的转换函数,优化器应该能够将其转换为无操作,因为它知道没有其他代码可以引用该数据记忆。

<'a, T> impl From<ListNode<'a, T>> for TreeNode<'a, T> {
     fn from(other: ListNode<'a, T>) -> ListNode<'a, T>> {
         ListNode {
             before: other.left_child,
             after: other.right_child,
             data: other.data,
         }
     }
}

您绝对应该对此进行基准测试以确保,但优化器拥有使其成为无操作所需的所有信息,而且很可能会这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多