在结构的定义中使用静态整数

时间:2014-08-30 17:46:44

标签: generics rust

我正在尝试将一些C ++代码迁移到Rust。我尝试了很多不同的方法,但都没有编译。

我想要一个可以处理不同类型的通用模板,并且具有可调整的总大小和静态字段(const表达式)Capacity

template<class KeyType, class ValueType, int PageSize>
struct BplusTreeLeaf {
    static const uint16_t Capacity = (PageSize-16)/(sizeof(KeyType)+sizeof(ValueType));
    KeyType keys[Capacity];
    ValueType values[Capacity];
};

我想从外面访问容量:

for(int i = 0; i < BplusTreeLeaf<x, y, 4096>::Capacity; i ++) { ... }

似乎没有办法在Rust中做这样的事情,或者至少在我对Rust的理解中:

    结构中不允许
  • static,文档告诉我使用宏
  • 只有类型可以在Rust中“模板化”,而不是值或表达式。我甚至无法将总大小作为参数传递给结构定义

据我所知:

macro_rules! BplusTreeLeaf {
    ($KeyType:ident, $ValueType:ident, $PageSize:expr) => {
        static Capacity_: u16 = ($PageSize - 16) / (std::mem::size_of::<$KeyType>() + std::mem::size_of::<$ValueType>());
        struct BplusTreeLeaf_ {
            keys: [$KeyType, ..Capacity_],
            values: [$ValueType, ..Capacity_],
        }
    }
}

BplusTreeLeaf!(u64, u64, 4096)

编译器产生“向量长度的预期常量expr”这是不正确的,因为我没有对Capacity_使用“mut”,所以它必须是一个const表达式。即使它可行,Capacity_BplusTreeLeaf_仍将在全局范围/命名空间中。

我是否误解了Rust设计中的一些基本内容,或者这是不可能的?如果现在不可能,有什么计划作为未来的功能,还是我应该继续使用C ++ 11?

2 个答案:

答案 0 :(得分:1)

您要寻找的主要功能称为const generics。它是公认的RFC,但是要使用它,还需要做很多工作。

如前所述,您可以创建一个宏,该宏将创建具有特定容量的一次性类型:

macro_rules! make_leaf {
    ($name:ident, $capacity:expr) => {
        struct $name<K, V> {
            keys: [K; $capacity],
            values: [V; $capacity],
        }

        impl<K, V> $name<K, V> {
            const CAPACITY: usize = $capacity;
        }
    }
}

make_leaf!(BplusTreeLeaf16, 16);
make_leaf!(BplusTreeLeaf32, 32);

fn main() {
    println!("{}", BplusTreeLeaf16::<u8, f32>::CAPACITY);
    println!("{}", BplusTreeLeaf32::<i32, bool>::CAPACITY);
}

答案 1 :(得分:0)

这个问题很旧,但仍然有效。您可以使用lazy_static条板箱。

常规静态变量必须使用常量表达式初始化,其中可能包含常量函数。这使它们可以在编译时进行评估,然后烘焙为二进制文件。但是,这有很多限制,例如没有堆分配。

您希望在程序首次运行时评估常数。像这个例子一样,直接从箱子的页面开始:

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
}

fn main() {
    // First access to `HASHMAP` initializes it
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());

    // Any further access to `HASHMAP` just returns the computed value
    println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap());
}
相关问题