我需要一个函数来获取 Option
通用类型 T
实现了特征 std::iter::IntoIterator
.
一个天真的实现可能如下所示(是的,解包会在 None
上出现 panic ):
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
还是使用某种默认值?
最佳答案
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>
,而是它自己的一个枚举:
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
接受任何可以转换的东西 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
值并使用 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
trait 实现,我们从不构造它,所以我们选择哪一个是无关紧要的,只要它满足 IntoIterator
。绑定(bind)。
当然,您仍然希望能够调用 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,
}
}
}
有了这些,您的 API 就干净了,允许 main()
看起来像这样(playground):
fn main() {
let v = vec![1i32, 2, 3];
print_iter(Some(v));
print_iter(Ignore);
}
关于generics - 在使用 Option::None 时,有没有办法提示编译器使用某种默认泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58593042/