我正在研究一个小型解释器,我想在堆栈中表示一些类型,其他类型是指针。这是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中代表这样的东西?枚举类型看起来很棒,但它们似乎不允许扩展。没有标记的工会似乎非常重要,而且帮助不大。有什么方法可以获得这种堆栈上的行为(从而减少数学运算期间的大量分配),同时仍然允许运行时扩展?
答案 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() {}