当使用Option :: None时,是否有一种方法可以提示编译器使用某种默认的泛型类型?

Mas*_*ath 4 generics traits option rust

我需要一个获取实现trait Option的泛型类型的函数。一个幼稚的实现可能看起来像以下内容(是的,解包可能会引起恐慌):Tstd::iter::IntoIteratorNone

fn main() {
    let v = vec![1i32, 2, 3];
    print_iter(Some(v));
    print_iter(None);
}

fn print_iter<T: IntoIterator<Item = i32>>(v: Option<T>) {
    for e in v.unwrap() {
        println!("{}", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

操场上测试。

这可以按预期工作Some(...),但因以下原因而失败None

error[E0282]: type annotations needed
 --> src/main.rs:4:5
  |
4 |     print_iter(None);
  |     ^^^^^^^^^^ cannot infer type for `T`
Run Code Online (Sandbox Code Playgroud)

T在这些情况下,显然类型是未知的。一个人可以使用,print_iter::<Vec<i32>>(None);但这并不是真正的习惯,因为这提供了一些不基于任何东西的任意类型...

有什么方法可以向编译器暗示我不在乎None或使用某种默认值吗?

use*_*342 5

有什么方法可以向编译器暗示我不在乎None或使用某种默认值吗?

您可以实现自己的非通用值作为默认值。对于初学者,我们假设print_iter不接受Option<T>,而是一个自己的枚举:

enum PrintArg<T> {
    Ignore,
    Use(T),
}

fn print_iter<T: IntoIterator<Item = i32>>(v: PrintArg<T>) {
    if let PrintArg::Use(v) = v {
        for e in v {
            println!("{}", e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这还不能解决问题,因为如果传递PrintArg::Ignoreprint_iter(),您回到第一个平方-编译器无法推断T。但是使用您自己的类型,您可以轻松地更改print_iter为接受可以转换 PrintArg以下内容的任何内容:

fn print_iter<T, V>(v: T)
where
    T: Into<PrintArg<V>>,
    V: IntoIterator<Item = i32>,
{
    if let PrintArg::Use(v) = v.into() {
        for e in v {
            println!("{}", e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

进行此修改后,您可以创建一个虚拟非泛型Ignore值,并使用该From特征将其转换为您选择的PrintArg::Ignore<T>with T,例如:

struct Ignore;

impl From<Ignore> for PrintArg<Vec<i32>> {
    fn from(_v: Ignore) -> Self {
        PrintArg::Ignore
    }
}
Run Code Online (Sandbox Code Playgroud)

Ignore非泛型一样,其使用不需要(或接受)<T>。尽管我们确实必须PrintArg<T>Fromtrait实现中发明一种类型,但我们从不构造它,因此,只要满足IntoIterator边界,我们选择哪种类型就无关紧要。

当然,你还是会希望能够调用print_iter()Some(...),所以你也需要定义的转换Option<T>PrintArg<T>

impl<T> From<Option<T>> for PrintArg<T> {
    fn from(v: Option<T>) -> Self {
        match v {
            Some(v) => PrintArg::Use(v),
            None => PrintArg::Ignore,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这些之后,您的API就变得干净了,main()看起来像这样(操场):

fn main() {
    let v = vec![1i32, 2, 3];
    print_iter(Some(v));
    print_iter(Ignore);
}
Run Code Online (Sandbox Code Playgroud)