我想获得Rust中数组的所有维度的大小,但我不确定如何解决这个问题。我能够使用x.len()
获取数组的长度,但我需要以某种方式递归地执行此操作。
我希望能够做到这样的事情:
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
// [2, 3]
形状类似[[1], [2, 3], [4, 5, 6]]
的切片应该会出错。
答案 0 :(得分:3)
对于每种可能的嵌套深度,都不可能以通用方式执行此操作。 Rust是一种静态类型语言,因此您必须知道输入和输出类型。 [1]
的输入类型是什么?[[1]]
的输入类型是什么?同样,相应的输出类型是什么?
我最接近的是具有相关类型的特征。这允许为特定类型实现它,然后关联另一种输出类型:
trait Thing {
type Dimensions;
fn thing(self) -> Self::Dimensions;
}
但是,一旦实施它,就会遇到问题:
impl<'a, T> Thing for &'a[T] {
type Dimensions = usize;
fn thing(self) -> usize {
self.len()
}
}
impl<'a, T> Thing for &'a[&'a[T]] {
type Dimensions = [usize; 2];
fn thing(self) -> Self::Dimensions {
[self.len(), self[0].len()]
}
}
error[E0119]: conflicting implementations of trait `Thing` for type `&[&[_]]`:
--> src/main.rs:14:1
|
6 | impl<'a, T> Thing for &'a[T] {
| - first implementation here
...
14 | impl<'a, T> Thing for &'a[&'a[T]] {
| ^ conflicting implementation for `&[&[_]]`
这是因为&[[T]]
是&[T]
。
你也可以考虑尝试一些递归的东西,但是没有办法说&[T]
并且知道T
是否可以进一步迭代。如果您具有HasLength
特征和DoesntHaveLength
特征,则不会阻止您实现单个类型的两个特征。因此,你再次被阻止。
以下是使用专业化的部分尝试:
#![feature(specialization)]
trait Dimensions: Sized {
fn dimensions(self) -> Vec<usize> {
let mut answers = vec![];
self.dimensions_core(&mut answers);
answers
}
fn dimensions_core(self, &mut Vec<usize>);
}
impl<'a, T> Dimensions for &'a [T] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
}
}
impl<'a, T> Dimensions for &'a [T]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(self.len());
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 2] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2)
}
}
impl<'a, T> Dimensions for [T; 2]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(2);
self[0].dimensions_core(answers);
}
}
impl<'a, T> Dimensions for [T; 3] {
default fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3)
}
}
impl<'a, T> Dimensions for [T; 3]
where T: Dimensions + Copy
{
fn dimensions_core(self, answers: &mut Vec<usize>) {
answers.push(3);
self[0].dimensions_core(answers);
}
}
// Also implement for all the other sizes of array as well as `Vec`
fn main() {
let x = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", x.dimensions());
let x = [[1, 2], [3, 4], [5, 6]];
println!("{:?}", x.dimensions());
}
它有一个明显的缺点,你仍然需要为每个数组大小实现特征,以便获得专业化。
我猜你是来自一种高度动态的语言。不同的语言有不同的优点和缺点。在Rust中,您知道您的输入类型,因此该函数无法知道我的类型的嵌套。如果它会收到Vec<T>
或Vec<&[Vec<T>]>
,我会提前知道嵌套的深度,所以我可以编写一个返回每个嵌套长度的函数:
fn depth3<A, B, C, T>(a: A) -> [usize; 3]
where A: AsRef<[B]>,
B: AsRef<[C]>,
C: AsRef<[T]>
{
let a = a.as_ref();
// All of these should check that the length is > 1
// and possibly that all children have same length
let b = a[0].as_ref();
let c = b[0].as_ref();
[a.len(), b.len(), c.len()]
}
fn main() {
let x = [[[1], [2], [3]], [[4], [5], [6]]];
println!("{:?}", depth3(&x));
}
这个函数和我想的一样通用 - 你传递对数组,切片,向量或这些类型的直接值的引用。事实上,我想不出一种方法甚至可以定义具有未知深度的切片/矢量/数组。我想要做一些类似的事情你必须引入一些带有间接性的新类型(可能是一个枚举),这样你就可以拥有一个非无限大小。
答案 1 :(得分:1)
数组定义为[T]
,T
不能同时为[U; 2]
和[U; 3]
。这意味着您甚至无法通过此编译过程。
如果您使用Vec<Vec<T>>
作为@Shepmaster提示,则可以执行以下操作。
fn main() {
let x = vec![vec![1, 2, 3], vec![4, 5]];
println!("{:?}", get_2d_dimension(&x));
}
fn get_2d_dimension<T>(arr: &[Vec<T>]) -> Result<(usize, usize), &str> {
let rows = arr.len();
if rows <= 1 {
return Err("Not 2d");
}
let cols = arr[0].len();
if arr.iter().skip(1).filter(|v| v.len() == cols).count() != rows - 1 {
Err("Not square.")
} else {
Ok((rows, cols))
}
}