我有两个(非常大)相同类型的数组foo
和bar
。为了能够编写一些不错的代码,我想获得两个数组串联的只读片result
。此操作必须在O(1)时间和空间中运行。
result
的数组访问权限也必须在O(1)中。更一般地说,如果result
是k
数组切片的串联,则result
的任意数组访问应该在O(k
)中运行。
我不想复制foo
和bar
的任何元素。
这似乎很容易实现到Rust核心,但没有多少搜索为我带来了解决方案。
答案 0 :(得分:10)
没有预定义的类型,但您可以通过为包含两个切片的类型实现Index
特征来轻松创建自己的类型:
use std::ops::Index;
struct Slice<'a, T: 'a>(&'a[T], &'a[T]);
impl<'a, T: 'a> Index<usize> for Slice<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &T {
if index < self.0.len() {
&self.0[index]
} else {
&self.1[index - self.0.len()]
}
}
}
更一般地说,如果
result
是k
数组切片的串联,则result
的任意数组访问应该在O(k
)中运行。
如果切片连接为O(log(k))
,则可以在O(k)
中获取切片访问权限,方法是创建一个包含切片累积长度的数组,并使用二进制搜索来查找要索引的实际切片成。
这需要一个宏,因为我们还没有足够好的常量评估器,也没有值泛型。
答案 1 :(得分:3)
对于n个数组,您可以使用Vec
实现它,如下所示:
use std::ops::Index;
struct VecSlice<'a, T: 'a>(Vec<&'a [T]>);
impl<'a, T> Index<usize> for VecSlice<'a, T> {
type Output = T;
fn index(&self, mut index: usize) -> &T {
for slice in self.0.iter() {
if index < slice.len() {
return &slice[index];
} else {
index -= slice.len();
}
}
panic!("out of bound");
}
}
然后像数组一样访问它,只是不要走出界限。
fn main() {
let a1 = [0, 1, 2];
let a2 = [7, 8, 9];
let a = VecSlice(vec!(&a1, &a2));
println!("{}", a[4]);
}
打印出来
8
答案 2 :(得分:2)
如果你要求结果是一个真正的切片,我担心你所要求的几乎是不可能的。切片是内存块的视图。连续的记忆。如果您想通过组合另外两个切片来创建新切片,则必须将内容复制到新位置,以便获得新的连续内存块。
如果您对通过复制concat
进行连接感到满意,则会在切片上提供方法join
和Clone
,只要它们实现{{1},就可以在自定义类型的切片上使用}}:
#[derive(Clone, PartialEq, Debug)]
struct A {
a: u64,
}
fn main() {
assert_eq!(["hello", "world"].concat(), "helloworld");
assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
assert_eq!([[A { a: 1 }, A { a: 2 }], [A { a: 3 }, A { a: 4 }]].concat(),
[A { a: 1 }, A { a: 2 }, A { a: 3 }, A { a: 4 }]);
}
请注意,即使SliceConcatExt
不稳定,方法本身也是稳定的。因此,如果复制正常,没有理由不使用它们。如果你不能复制你不能得到一个切片。在这种情况下,您需要创建一个包装器类型,如the answer of ker中所述。