generics - 在使用 Option::None 时,有没有办法提示编译器使用某种默认泛型类型?

标签 generics rust option-type traits

我需要一个函数来获取 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::Ignoreprint_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/

相关文章:

java - 了解泛型以及类型检查的工作原理

c - 如何在 Rust 中创建静态库以链接到 Windows 中的 C 代码?

parsing - 使用 `nom` 处理自定义枚举类型是否有意义?

design-patterns - 协议(protocol):为什么一致性检查和可选要求需要@ObjC?

c# - 如何使用特定类型的泛型类来注释代码

c# - 一般的 TryParse 可空类型

c# - 使用 Type 对象创建泛型

csv - 尝试写入 CSV 记录时出现错误 "the trait ` std::convert::AsRef<[u8] >` is not implemented for ` u 8`"

ios - 触摸开始错误;我触摸屏幕的任何地方游戏都会崩溃

java - rxjava2的Maybe和Optional有什么区别?