我需要一个函数,该函数获取实现特征Option
的通用类型T
的std::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
或使用某种默认值?
有没有办法向编译器提示我不在乎
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
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