2017-07-14 14 views
1

私は小さなインタプリタで作業しています。構造体の残りのためのタグとしてランタイムで定義されたメンバでタグ付きの共用体

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行為:ここでは、C++で次のようになります。 integer、boolean、nilsなどのものはスタックに渡すことができますが、文字列やオブジェクトなどの大きなものは参照渡しできます。

インタープリタは、実行時にREF_START_TYPEの新しい型を作成します。新しいタイプが作成されると、ある内部カウンタに値を追加し、次のタイプのIDになり、そのタイプがポインタであると予想されます。

どうすればRustでこれを表現できますか?列挙型はすばらしいようですが、拡張を許可していないようです。タグなし組合は非常にWIPで、あまり役に立たないようです。実行時の拡張を可能にしながら、このようなオンスタック動作を得ることができます(これにより、数学演算中の割り当て量を削減できます)。あなたはあなたがRuntimeTypeはポインタのみが含まれていることを確認か、すぐにそれをボックスに(Runtime(TypeId, Box<RuntimeType>),)を選択することができ

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

ような何かをしたいが、同じ最終結果を持っているよう

+0

Cは、いずれかの組合の種類のランタイム拡張をサポートしていないので、私はここでの問題は本当に錆固有ではないと思います。しかし、あなたが避けようとしている配分であれば、 https://doc.rust-lang.org/nomicon/exotic-sizes.html –

答えて

3

はそれが鳴ります。

Boxが含まれている場合、この構造体は64ビットマシンで24バイトを占有します。残念ながら、TypeIdと列挙型の判別式が同じ場所に存在するはずであることをコンパイラに知らせる方法はありません。代わりに、余分なスタックサイズよりも逆参照が悪くないことが測定値に示されている場合は、TypeIdBox<RuntimeType>に移動することを選択できます。これは、列挙型に直接組み込む他の型に応じて非常に順応性があります。たとえば、Vecは3ポインター分のスタックスペースです。それが含まれていれば、より多くの値をインライン展開することができます。

トリックになる:RuntimeTypeは何ですか?あなたは私が推測するのに十分なほどの問題を記述していません。それは具体的なタイプかもしれないし、ボックス化された形質オブジェクトになるかもしれない。

Aもう少し複雑な例:

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() {} 
関連する問題