Using a static integer in a structure definition

I am trying to port C ++ code to Rust. I tried many different approaches, but not one of them compiles.

I want a generic template that can handle various types and has an adjustable total size with a static field (Set expression) 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]; }; 

I want to access the tank outside:

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

There seems to be no way in Rust to do something like this, or at least in my understanding of Rust:

  • static not allowed in the structure and the documentation tells me to use macros
  • in Rust, only types are "template", not values ​​or expressions. I can't even pass the total size as an argument to define the structure

This is how much I got:

 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) 

The compiler yields the "expected constant expr for the length of the vector", which is incorrect because I did not use "mut" for Capacity_ , so it should be a const expression. Even if it works, Capacity_ and BplusTreeLeaf_ will still be in the global scope / namespace.

Am I misunderstood something basic in Rust design or is it just not possible? If this is not possible now, is something planned as a future function or should I stay with C ++ 11?

+5
source share
2 answers

The main function you are looking for is called const generics . This is an accepted RFC, but a lot of work needs to be done before it is available for use.

As you mentioned, you can create a macro that will create one-time types with a specific capacity:

 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); } 

See also:

+1
source

This question is old, but still relevant. You can use the lazy_static box.

Normal static variables must be initialized using constant expressions, which may include constant functions. This allows them to be evaluated at compile time and baked to a binary file. However, this imposes many limitations, such as the lack of heap allocation.

You want to evaluate the constant when you first start the program. As in this example, right from the mailbox page:

 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()); } 
0
source

Source: https://habr.com/ru/post/1201480/


All Articles