使用IntoIterator特征接受一片切片元组的函数

Tim*_*ann 4 rust

我有一个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)

更换JVec<f32>的作品,但是这不是我想要走的路.

有没有办法处理这个,以便我可以按照我提到的方式调用该函数?起初我认为这可以通过更高级别的特征界限来解决,但这些仅适用于终身参数.

如果它可以工作,我该如何正确处理这些嵌套IntoIterator?我怎么称呼J::into_iter()

kaz*_*ase 6

功能定义非常好; 问题是如何构造参数.没有这个功能它也不起作用:

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)