types - 从函数返回泛型而在rust中没有泛型参数

标签 types rust type-inference

我目前正在尝试在Rust中编写一个小函数,该函数将通过简单的LISP风格的计算器语言的 token 返回迭代器。我没想到会遇到编译错误。
我第一次编写该函数的尝试是:

fn tokenizer_for<'a, I>(s: &'a str) -> Peekable<I> where I: Iterator<Item=&'a str> {
    s.split_whitespace()
        .flat_map(
            |word| {
                word.replace("(", "( ").replace(")", " )").split_whitespace()
            }
        )
        .peekable()
}
但是rustc回答:
error[E0308]: mismatched types
  --> src/lib.rs:4:5
   |
3  |   fn tokenizer_for<'a, I>(s: &'a str) -> Peekable<I> where I: Iterator<Item=&'a str> {
   |                        -                 ----------- expected `std::iter::Peekable<I>` because of return type
   |                        |
   |                        this type parameter
4  | /     s.split_whitespace()
5  | |         .flat_map(
6  | |             |word| {
7  | |                 word.replace("(", "( ").replace(")", " )").split_whitespace()
8  | |             }
9  | |         )
10 | |         .peekable()
   | |___________________^ expected type parameter `I`, found struct `std::iter::FlatMap`
   |
   = note: expected struct `std::iter::Peekable<I>`
              found struct `std::iter::Peekable<std::iter::FlatMap<std::str::SplitWhitespace<'_>, std::str::SplitWhitespace<'_>, [closure@src/lib.rs:6:13: 8:14]>>`
   = help: type parameters must be constrained to match other types
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
我发现在返回类型中使用impl是可行的(我更喜欢):
fn tokenizer_for(s: &str) -> Peekable<impl Iterator<Item=&str>> {
    s.split_whitespace()
        .flat_map(
            |word| {
                word.replace("(", "( ").replace(")", " )").split_whitespace()
            }
        )
        .peekable()
}
但是我曾希望能够在这两个选项之间进行选择,即使后者似乎可行,甚至可能不会产生泛型函数。
在前一种情况下,为什么不能使用where子句指定泛型?
我已经使用where子句来约束以前出现在返回类型中的通用参数。仅当通用参数也出现在函数的参数中时,这才起作用吗?
任何更多解释这种区别的细节的引用文献都将特别有帮助。

最佳答案

在Rust中,当您在Item<...>列表中指定了生存期或类型参数时,将在使用站点上选择这些生存期或类型参数。
该函数签名表明函数的调用者可以选择I是什么类型:

fn tokenizer_for<'a, I>(s: &'a str) -> Peekable<I> where I: Iterator<Item=&'a str>;
但这不能编译,因为返回类型实际上是对Iter::peekable()的调用的返回类型(即,来自错误消息std::iter::Peekable<std::iter::FlatMap<std::str::SplitWhitespace<'_>, std::str::SplitWhitespace<'_>, [closure@src/lib.rs:6:13: 8:14]>>的类型)。
另一方面,此签名表示返回类型仅仅是实现Iterator<Item=&str>>的一种:
fn tokenizer_for(s: &str) -> Peekable<impl Iterator<Item=&str>>;
调用者无法选择那是什么类型。编译器从函数体中推断出实际的类型。

关于types - 从函数返回泛型而在rust中没有泛型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62747289/

相关文章:

c# - 为什么 VB Parallel.ForEach 不能推断我的循环项类型?

java - 如何将标准 Java 类型映射到 SQL 类型?

c - 无法获取字符串的第 n 个字符

rust - 正确解析 Clap ArgMatches 的惯用使用rust 方法

testing - 如何只运行库和集成测试?

rust - 我为另一个特征实现了一个特征,但不能从两个特征调用方法

haskell - 如何理解 "ap = liftM2 id"的类型推断?

dart - Dart 应该推断类成员类型吗?

c++ - 指针:C++ 要求所有声明都有类型说明符

scala - Scala 的 "type"关键字是什么意思?