带有运行时定义成员的标记联合

时间:2017-07-14 22:46:51

标签: rust

我正在研究一个小型解释器,我想在堆栈中表示一些类型,其他类型是指针。这是C ++中的样子:

enum {
  NIL_TYPE,
  INT_TYPE,
  REF_TYPE_START,
}

union Data 
{
  int int_val;
  void *obj_val
}

struct Object
{
  size_t _type_id;
  Data _data;
}

_type_id充当结构其余部分的标记。诸如整数,布尔值,nils等之类的东西可以在堆栈上传递,而字符串和对象之类的更大的东西可以通过引用传递。

解释器将在运行时创建新类型,这是REF_START_TYPE的用途。当创建一个新类型时,我们将向一个内部计数器添加一个值,它将成为下一个类型id,并且该类型应该是一个指针。

我怎样才能在Rust中代表这样的东西?枚举类型看起来很棒,但它们似乎不允许扩展。没有标记的工会似乎非常重要,而且帮助不大。有什么方法可以获得这种堆栈上的行为(从而减少数学运算期间的大量分配),同时仍然允许运行时扩展?

1 个答案:

答案 0 :(得分:3)

听起来你想要像

这样的东西
enum Object {
    Nil,
    Int(i32),
    Runtime(TypeId, RuntimeType),
}

您可以确保RuntimeType仅包含指针或选择立即将其设置为Runtime(TypeId, Box<RuntimeType>),),但结果相同。

如果它包含Box,则此结构在64位计算机上占用24个字节。不幸的是,我无法通知编译器TypeId和枚举的判别式应该位于同一位置。如果您的测量显示取消引用比额外的堆栈大小更差,您可以选择将TypeId移动到Box<RuntimeType>。这一切都非常具有可塑性,具体取决于您直接嵌入枚举的其他类型。例如,Vec是三维指针的堆栈空间。如果包括在内,您可以放弃更多的值。

诀窍变成:RuntimeType是什么?你还没有足够的描述这个问题。它可能是一个具体的类型,或者它可能最终成为一个盒装的特征对象。

稍微完整的例子:

struct RuntimeType;
type TypeId = u64;

enum Object {
    Nil,
    Int(i32),
    Runtime(TypeId, RuntimeType),
}

impl Object {
    fn type_id(&self) -> TypeId {
        use Object::*;

        match *self {
            Nil => 0,
            Int(..) => 1,
            Runtime(id, ..) => id,
        }
    }
}

fn main() {}