当使用Option :: None时,是否有一种方法可以提示编译器使用某种默认的泛型类型? [英] Is there a way to hint to the compiler to use some kind of default generic type when using Option::None?
问题描述
我需要一个函数,该函数获取实现特征std::iter::IntoIterator
的通用类型T
的Option
.
一个幼稚的实现可能看起来像下面的样子(是的,展开会在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
以接受可以进行转换 插入 PrintArg
:
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屋!