2017-07-14 17 views
1

我正在研究一個小解釋器,我想在其他人指針的情況下表示堆棧上的某些類型。下面是它看起來像在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的用途。當創建一個新類型時,我們會向某個內部計數器添加一個值,並且該值將成爲下一個類型標識,並且該類型應該是一個指針。

如何在Rust中表示這樣的內容?枚舉類型看起來很棒,但它們似乎不允許擴展。無標籤的工會似乎是一個在製品,並沒有太大的幫助。有什麼辦法可以獲得這種堆棧行爲(從而減少數學運算期間的大量分配),同時仍允許運行時擴展?

+0

C不支持聯合類型的運行時擴展要麼,所以我不認爲這裏的問題是真正的防鏽專用。但是如果你想避免的是分配,請看例如https://doc.rust-lang.org/nomicon/exotic-sizes.html –

回答

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() {} 
相關問題