我正在尝试从头开始在Rust中实现一个玩具散列图,并且实际上正在初始化我需要的桶。我已经使用了一些带有其他原语(如u8)的数据桶(在下面的代码片段中显示)。
我无法弄清楚的是如何告诉编译器为我分配一个包含其他向量的可变向量 - 在本例中为~str
。此代码编译,但在运行时因index out of bounds
错误而失败。
static DEFAULT_NUMBER_OF_BUCKETS: uint = 64;
static DEFAULT_VALUE_LENGTH: uint = 32; //unused
struct NaiveHashMap {
hashmap_size: uint, //unused.
string_capacity: uint, //unused.
//contents: ~[ u8 ]
contents: ~[ ~str ]
}
impl NaiveHashMap {
fn new(hash_size: uint, string_size: uint) -> NaiveHashMap {
NaiveHashMap {
hashmap_size: hash_size, //unused
string_capacity: string_size, //unused
//contents: ~[ 0, ..DEFAULT_NUMBER_OF_BUCKETS ]
contents: std::vec::with_capacity::<~str>(DEFAULT_NUMBER_OF_BUCKETS)
}
}
fn get_hash(&self, key: &str) -> u32 {
let hash: u32 = jenkins_hash(key);
hash % self.hashmap_size.to_u32().unwrap()
}
//fn add(&mut self, key: &str, value: u8) {
fn add(&mut self, key: &str, value: ~str) {
let bucket = self.get_hash(key);
self.contents[bucket] = value;
}
//fn get(self, key: &str) -> u8 {
fn get(&self, key: &str) -> ~str {
let bucket = self.get_hash(key);
self.contents[bucket].clone()
}
}
如果没有调用不安全的from_buf分配或只是复制std Hashmap lib,我不确定如何继续。
我意识到最好在课堂上传递一个<T>
,这样才能灵活,但更喜欢先把这一点弄清楚。
编辑:修改了get()以避免捕获整个结构。
答案 0 :(得分:6)
据我所知,你想构建一个给定长度的向量,用索引写一些东西。
除非为向量的每个元素指定默认值,否则无法在Rust中安全地执行此操作。它与~[u8]
一起使用,因为您确实指定了默认值(零),因为u8
是可隐式复制的:
[0, ..DEFAULT_NUMBER_OF_BUCKETS]
但您对~str
的期望值是多少?它是一个指针,并且指针在Rust中不能等于null,这可能是指针最自然的默认值。我认为~str
的下一个最自然的值是~""
,即一个空字符串。您可以使用它来创建N
字符串的向量:
vec::from_elem(N, ~"")
这将创建一个空盒装字符串的向量。但它也意味着N分配,而不是你不应该考虑的事情。
但是,您不能使用任意类型T
执行此操作,因为通常任意类型T
没有任何默认值。此外,任意T
也可能不Clone
,这是from_elem()
所要求的。但您可以从T
创建另一种类型,它具有默认值。您可以使用Option
:
contents: ~[Option<T>]
要克服不可克隆性,可以使用带有闭包的from_fn()
函数:
contents: vec::from_fn(N, |_| None)
BTW,它因“索引越界”错误而失败的原因是因为你正在使用with_capacity()
函数。此函数创建一个零长度的向量,但具有指定的容量。您可以在向量上使用push()
方法将元素追加到它的末尾,并且在达到其容量之前不会重新分配它,但是您无法访问添加元素的“外部”元素。