我正在使用一个小型解释器,我想在堆栈中表示某些类型,而其他类型则作为指针。这是在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
充当其余结构的标签。诸如整数, bool 值,nils等之类的东西可以在堆栈上传递,而诸如字符串和对象之类的较大的事物可以通过引用传递。解释器将在运行时创建新类型,这就是
REF_START_TYPE
的目的。创建新类型时,我们将向某个内部计数器添加一个值,该值将成为下一个类型ID,并且该类型应为指针。如何在Rust中表示类似的内容?枚举类型看起来很棒,但是它们似乎不允许扩展。未标记的工会似乎是一个在制品,而没有太多帮助。有什么办法可以得到这种堆栈上的行为(从而减少数学运算期间的大量分配),同时仍然允许运行时扩展?
最佳答案
听起来你想要类似的东西
enum Object {
Nil,
Int(i32),
Runtime(TypeId, RuntimeType),
}
您可以确保
RuntimeType
仅包含一个指针,或选择立即将其装箱(Runtime(TypeId, Box<RuntimeType>),
),但最终结果相同。如果它包含
Box
,则此结构在64位计算机上占用24个字节。不幸的是,我无法通知编译器TypeId
和枚举的判别式应位于同一位置。如果您的测量结果表明取消引用的程度比额外的堆栈大小小,则可以选择将TypeId
移到Box<RuntimeType>
中。这取决于所有直接嵌入枚举的其他类型,都是非常具有延展性的。例如,Vec
是3指针的堆栈空间。如果包含这些内容,则可以内联更多值。诀窍变成了:
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() {}