是否可以在Rust中将一个结构的内存与另一个结构关联?

Ben*_* Z. 1 binary-tree linked-list type-punning rust

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

typedef struct tree{
    void* left_child;
    void* right_child;
    void* data;
}tree_t;
Run Code Online (Sandbox Code Playgroud)

对于树,以及:

typedef struct list{
    void* before;
    void* after;
    void* data;
}list_t;
Run Code Online (Sandbox Code Playgroud)

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

tree_t mytree;
/*fill tree*/
list_t *list_p;
list_p = (list_t)&mytree;
/*change pointers accordingly*/
Run Code Online (Sandbox Code Playgroud)

但是如何在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>>>;
Run Code Online (Sandbox Code Playgroud)

列表将是:

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

type ListLink<'a, T> = Option<Box<ListNode<'a, T>>>;
Run Code Online (Sandbox Code Playgroud)

但是,现在如何才能有效地将它们转换为原位?

Pet*_*all 5

但是如何在Rust中做这样的事情?如果不使用不安全的代码,是否有可能?直到现在我有了我的树

直接执行相同的操作,您将需要使用不安全的代码。该功能std::mem::transmute正是您想要的。问题是不能保证Rust中的结构布局,因此以下通常是未定义行为:

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

但是,通过使用以下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,
}
Run Code Online (Sandbox Code Playgroud)

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


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

<'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,
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

您绝对应该对此进行基准测试以确保确定,但是优化器具有将其变为无操作状态所需的所有信息,而且很有可能会做到这一点。