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

问题描述 投票:3回答:2

我需要一个函数,该函数获取实现特征Option的通用类型Tstd::iter::IntoIterator。一个幼稚的实现可能如下所示(是的,展开会在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);
    }
}

测试playground

[这对于Some(...)正常工作,但对None无效,带有:

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);,但这并不是真正的习惯,因为这提供了一些不基于任何内容的任意类型...

有没有办法向编译器提示我不在乎None或使用某种默认值?

generics rust traits option
2个回答
3
投票

有没有办法向编译器提示我不在乎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);
        }
    }
}

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

的任何内容。
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值,并使用From特征以您选择的From定义其向PrintArg::Ignore<T>的转换-例如:

T

由于struct Ignore; impl From<Ignore> for PrintArg<Vec<i32>> { fn from(_v: Ignore) -> Self { PrintArg::Ignore } } 是非泛型的,因此它的使用不需要(或接受)Ignore。尽管我们确实必须在<T>特征实现中为PrintArg<T>创建一个类型,但我们从不构造它,因此,只要满足From界限,我们选择哪种类型就无关紧要。

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

PrintArg<T>

有了这些,您的API很干净,允许impl<T> From<Option<T>> for PrintArg<T> { fn from(v: Option<T>) -> Self { match v { Some(v) => PrintArg::Use(v), None => PrintArg::Ignore, } } } 看起来像这样(main()):

playground

1
投票

fn main() { let v = vec![1i32, 2, 3]; print_iter(Some(v)); print_iter(Ignore); } 值没有问题。

无法推断您的变量类型通常不会发生,这只是一个问题。唯一有问题的情况是,您直接传递None,并且没有类型变量。

您可以使用涡轮鱼指定类型:

None

但是您通常不需要;您通常的情况会是这样的:

print_iter::<Vec<i32>>(None);

let a: Option<Vec<i32>> = None;
print_iter(a);

并且两种构造都没有问题。

Now(在问题编辑之后),如果您确实希望能够在不指定类型的情况下传递print_iter(some_function_returning_an_option()); ,例如,将其作为文字标记,则可以定义一个宏:

None
© www.soinside.com 2019 - 2024. All rights reserved.