当使用Option :: None时,是否有一种方法可以提示编译器使用某种默认的泛型类型? [英] Is there a way to hint to the compiler to use some kind of default generic type when using Option::None?

查看:69
本文介绍了当使用Option :: None时,是否有一种方法可以提示编译器使用某种默认的泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个函数,该函数获取实现特征std::iter::IntoIterator的通用类型TOption. 一个幼稚的实现可能看起来像下面的样子(是的,展开会在None上惊慌):

I need a function that gets an Option of an generic type T that implements the trait std::iter::IntoIterator. A naive implementation could look like the following (yes, the unwrap would panic on None):

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);
    }
}

操场.

这对于Some(...)可以正常工作,但是对于None却失败,

This works as expected for Some(...), but fails for None with:

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

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

Obviously the type of T is unknown in those cases. One could use print_iter::<Vec<i32>>(None); but this does not feel really idiomatic, because this gives some arbitrary type that isn't based on anything...

是否可以向编译器暗示我不在意None或使用某种默认值?

Is there any way to hint to the compiler that I don't care for None or use some kind of default?

推荐答案

是否可以向编译器暗示我不在意None或使用某种默认值?

Is there any way to hint to the compiler that I don't care for None or use some kind of default?

您可以实现自己的非通用值作为默认值.首先,假设print_iter不接受Option<T>,而是它自己的枚举:

You can implement your own non-generic value to serve as the default. For starters, let's assume print_iter didn't accept Option<T>, but an enum of its own:

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);
        }
    }
}

这还不能解决问题,因为如果将PrintArg::Ignore传递给print_iter(),则返回第一个平方-编译器无法推断T.但是使用您自己的类型,您可以轻松地更改print_iter以接受可以进行转换

This doesn't solve the problem yet, because if you pass PrintArg::Ignore to print_iter(), you are back at square one - the compiler is unable to to infer the T. But with your own type, you can easily change print_iter to accept anything that can be converted into 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);
        }
    }
}

通过此修改,您可以创建一个虚拟的非通用Ignore值,并使用

With this modification, you can create a dummy non-generic Ignore value and use the From trait to define its conversion to a PrintArg::Ignore<T> with T of your choice - for example:

struct Ignore;

impl From<Ignore> for PrintArg<Vec<i32>> {
    fn from(_v: Ignore) -> Self {
        PrintArg::Ignore
    }
}

由于Ignore是非泛型的,因此它的使用不需要(或接受)<T>.尽管我们确实必须在From特征实现中为PrintArg<T>创建一个类型,但是我们从不构造它,因此,只要满足IntoIterator界限,我们选择的类型就无关紧要.

As Ignore is non-generic, its use doesn't require (or accept) a <T>. While we did have to invent a type for PrintArg<T> in the From trait implementation, we never construct it, so it's irrelevant which one we choose, as long as it satisfies the IntoIterator bound.

当然,您仍然希望能够使用Some(...)调用print_iter(),因此您还将定义Option<T>PrintArg<T>的转换:

Of course, you'll still want to be able to invoke print_iter() with Some(...), so you'll also define a conversion of Option<T> to 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,
        }
    }
}

有了这些,您的API就会很干净,允许main()看起来像这样(

With these in place, your API is clean, allowing main() to look like this (playground):

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

这篇关于当使用Option :: None时,是否有一种方法可以提示编译器使用某种默认的泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆