简体   繁体   English

如何编写带迭代器的 Rust 函数?

[英]How to write a Rust function that takes an iterator?

I'd like to write a function that accepts an iterator and returns the results of some operations on it.我想编写一个接受迭代器并返回对其进行某些操作的结果的函数。 Specifically, I'm trying to iterate over the values of a HashMap :具体来说,我试图遍历HashMap的值:

use std::collections::HashMap;

fn find_min<'a>(vals: Iterator<Item=&'a u32>) -> Option<&'a u32> {
    vals.min()
}

fn main() {
    let mut map = HashMap::new();
    map.insert("zero", 0u32);
    map.insert("one", 1u32);
    println!("Min value {:?}", find_min(map.values()));
}

But alas:可惜:

error: the `min` method cannot be invoked on a trait object
 --> src/main.rs:4:10
  |
4 |     vals.min()
  |          ^^^

error[E0277]: the trait bound `std::iter::Iterator<Item=&'a u32> + 'static: std::marker::Sized` is not satisfied
 --> src/main.rs:3:17
  |
3 | fn find_min<'a>(vals: Iterator<Item = &'a u32>) -> Option<&'a u32> {
  |                 ^^^^ `std::iter::Iterator<Item=&'a u32> + 'static` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=&'a u32> + 'static`
  = note: all local variables must have a statically known size

error[E0308]: mismatched types
  --> src/main.rs:11:41
   |
11 |     println!("Min value {:?}", find_min(map.values()));
   |                                         ^^^^^^^^^^^^ expected trait std::iter::Iterator, found struct `std::collections::hash_map::Values`
   |
   = note: expected type `std::iter::Iterator<Item=&u32> + 'static`
              found type `std::collections::hash_map::Values<'_, &str, u32>`

I get the same error if I try to pass by reference;如果我尝试通过引用传递,我会得到同样的错误; if I use a Box , I get lifetime errors.如果我使用Box ,我会遇到生命周期错误。

You want to use generics here:你想在这里使用泛型:

fn find_min<'a, I>(vals: I) -> Option<&'a u32>
where
    I: Iterator<Item = &'a u32>,
{
    vals.min()
}

Traits can be used in two ways: as bounds on type parameters and as trait objects.特征可以以两种方式使用:作为类型参数的边界和作为特征对象。 The book The Rust Programming Language has a chapter on traits and a chapter on trait objects that explain these two use cases. The Rust Programming Language 》一书有一章是关于traits的,还有一章是关于trait objects的,它们解释了这两个用例。

Additionally, you often want to take something that implements IntoIterator as this can make the code calling your function nicer:此外,您通常希望采用实现IntoIterator的东西,因为这可以使调用您的函数的代码更好:

fn find_min<'a, I>(vals: I) -> Option<&'a u32>
where
    I: IntoIterator<Item = &'a u32>,
{
    vals.into_iter().min()
}

Since Rust 1.26 impl Trait are available.自 Rust 1.26 impl Trait可用。 Here is a more compact version using impl Trait .这是使用impl Trait的更紧凑的版本。

use std::collections::HashMap;

fn find_min<'a>(vals: impl Iterator<Item = &'a u32>) -> Option<&'a u32> {
    vals.min()
}

fn main() {
    let mut map = HashMap::new();
    map.insert("zero", 0u32);
    map.insert("one", 1u32);
    println!("Min value {:?}", find_min(map.values()));
}

playground 操场

This behaviour is a little unintuitive from those with a Python background rather than, say, a C++ background, so let me clarify a little.对于那些具有 Python 背景而不是 C++ 背景的人来说,这种行为有点不直观,所以让我澄清一下。

In Rust, values are conceptually stored inside the name that binds them.在 Rust 中,值在概念上存储在绑定它们的名称中。 Thus, if you write因此,如果你写

let mut x = Foo { t: 10 };
let mut y = x;
x.t = 999;

yt will still be 10 . yt仍然是10

So when you write所以当你写

let x: Iterator<Item=&'a u32>;

(or the same in the function parameter list), Rust needs to allocate enough space for any value of type Iterator<Item=&'a u32> . (或在函数参数列表中相同),Rust 需要为Iterator<Item=&'a u32>类型的任何值分配足够的空间。 Even if this was possible, it wouldn't be efficient.即使这是可能的,它也不会有效。

So what Rust does instead is offer you the option to所以 Rust 所做的是为您提供选择

  • Put the value on the heap, eg.将值放在堆上,例如。 with Box , which gives Python-style semantics. with Box ,它提供了 Python 风格的语义。 Then you can take generically with &mut Iterator<Item=&'a u32> .然后你可以一般地使用&mut Iterator<Item=&'a u32>

  • Specialize each function invocation for each possible type to satisfy the bound.为每种可能的类型专门化每个函数调用以满足边界。 This is more flexible, since a trait reference is a possible specialization, and gives the compiler more opportunities for specialization, but means you can't have dynamic dispatch (where the type can vary dependent on runtime parameters).这更灵活,因为特征引用是一种可能的特化,并为编译器提供了更多的特化机会,但这意味着您不能进行动态分派(类型可以根据运行时参数而变化)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何编写需要一部分函数的函数? - How to write a function that takes a slice of functions? 如何在 Python 中编写一个没有 Pandas 的文件的函数? - How to write a function which takes files without Pandas in Python? 如何编写仅将枚举的一个变体作为输入的函数 - how to write a function that only takes one variant of the enum as input 如何编写一个 function 以文件名作为 Python 中的参数? - How to write a function that takes in the name of a file as the argument in Python? 如何编写一个模板函数,它接受一个数组和一个指定数组大小的int - How to write a template function that takes an array and an int specifying array size 如何编写一个包含2个字符串的函数,并将它们添加到相应数组的BEGINNING中 - how to write a function that takes 2 strings, and add them to the BEGINNING of the respective arrays 如何编写一个带有默认参数的lambda的泛型函数? - How to write a generic function that takes a lambda with a default argument? 如何编写带有任意数量参数的PHP函数? - How can I write a PHP function that takes an arbitrary number of parameters? 写一个 function 需要 2 个字符串 arguments - write a function that takes 2 string arguments 想编写一个以 csv 文件为参数的函数 - Want to write a function that takes a csv file as an argument
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM