我有一个f应该像这样调用的函数:
struct S;
let s = &S;
f(&[(s, &[0.1, 0.2, 0.3]), (s, &[0.5, 0.6])]);
Run Code Online (Sandbox Code Playgroud)
为了方便界面,我想f处理任何类型的IntoIterator.目前,我的签名是
fn f<'a, I, J: 'a>(iter: I)
where
I: IntoIterator<Item = &'a (&'a S, J)>,
J: IntoIterator<Item = &'a f32>
Run Code Online (Sandbox Code Playgroud)
遗憾的是,编译器将切片视为固定大小的数组,因此我收到此错误:
error[E0308]: mismatched types
--> sandbox/src/main.rs:142:33
|
142 | f(&[(s, &[0.1, 0.2, 0.3]), (s, &[0.5, 0.6])]);
| ^^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
= note: expected type `&[{float}; 3]`
found type `&[{float}; 2]`
Run Code Online (Sandbox Code Playgroud)
更换J用Vec<f32>的作品,但是这不是我想要走的路.
有没有办法处理这个,以便我可以按照我提到的方式调用该函数?起初我认为这可以通过更高级别的特征界限来解决,但这些仅适用于终身参数.
如果它可以工作,我该如何正确处理这些嵌套IntoIterator?我怎么称呼J::into_iter()?
功能定义非常好; 问题是如何构造参数.没有这个功能它也不起作用:
41 | let x = &[(s, &[0.1, 0.2, 0.3]), (s, &[0.5, 0.6])];
| ^^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
|
= note: expected type `&[{float}; 3]`
found type `&[{float}; 2]`
Run Code Online (Sandbox Code Playgroud)
编译器会看到外部切片的第一个元素,并推断该切片具有类型的元素(&S, &[{float}; 3]).这与长度为2的第二个元素冲突.它根本不知道它可以/应该使用更通用的任意切片&[{float}].
如果我们明确强制第一个元素的类型,它编译好:
f(&[(s, &[0.1f32, 0.2, 0.3] as &[f32]), (s, &[0.5, 0.6])]);
Run Code Online (Sandbox Code Playgroud)
或者,您可以传入迭代器,这也方便地实现IntoIterator:
f(&[(s, [0.1, 0.2, 0.3].iter()), (s, [0.5, 0.6].iter())]);
Run Code Online (Sandbox Code Playgroud)
当然,这两种方法都不是特别方便(尽管后者并不是太糟糕的IMO).如果目标是使用嵌套切片的函数,则可以将其定义为:
fn f2<T>(iter: &[(&S, &[T])]) {}
f2(&[(s, &[0.1, 0.2, 0.3]), (s, &[0.5, 0.6])]);
Run Code Online (Sandbox Code Playgroud)
你必须选择你的权衡:要么有一个方便地获取切片但拒绝其他迭代的函数,或者有一个函数可以进行任何迭代,但调用稍微麻烦一些.
如果您的函数使用新的impl Trait-syntax,则此建议也适用:
fn f<'a>(iter: impl IntoIterator<Item = &'a (&'a S, impl IntoIterator<Item = &'a f32> + 'a)>)
Run Code Online (Sandbox Code Playgroud)