我想构造一个与值关联的索引类型,该值是一个
usize
这样,从该值创建的任何向量,我都不需要检查索引。似乎幻影的生命周期可以用来做一些少量的依赖类型的编程,就像这样。这能行吗?还是有什么我没有考虑的?
换句话说,使用下面的模块是否不可能编写出内存不足的“安全”代码?
还有,有没有办法在没有单元参考的情况下做到这一点?
pub mod things {
use std::iter;
#[derive(Clone, Copy)]
pub struct ThingIndex<'scope>(usize, &'scope ());
pub struct Things {
nthings: usize,
}
pub struct ThingMapping<'scope, V>(Vec<V>, &'scope ());
impl Things {
pub fn in_context<F: FnOnce(&Things) -> V, V>(nthings: usize, continuation: F) -> V {
continuation(&Things { nthings })
}
pub fn make_index<'scope>(&'scope self, i: usize) -> ThingIndex<'scope> {
if i >= self.nthings {
panic!("Out-of-bounds index!")
}
ThingIndex(i, &())
}
pub fn make_mapping<'scope, V: Clone>(&'scope self, def: V) -> ThingMapping<'scope, V> {
ThingMapping(iter::repeat(def).take(self.nthings).collect(), &())
}
}
impl<'scope, V> ThingMapping<'scope, V> {
pub fn get<'a>(&'a self, ind: ThingIndex<'scope>) -> &'a V {
unsafe { &self.0.get_unchecked(ind.0) }
}
// ...
}
}
更新:
这似乎不起作用。我添加了一个我预计无法编译的测试,它编译时没有抱怨。有没有办法修复它并使其正常工作?如果我写一个宏呢?
#[cfg(test)]
mod tests {
use crate::things::*;
#[test]
fn it_fails() {
Things::in_context(1, |r1| {
Things::in_context(5, |r2| {
let m1 = r1.make_mapping(());
let i2 = r2.make_index(3);
assert_eq!(*m1.get(i2), ());
});
})
}
}
注:
in_context
大致基于Haskell的
runST
作用Haskell中的类型签名
朗斯特
要求
RankNTypes
.我想知道这是否是不可能的,因为Rust编译器不会与
兰开佩斯
.