【问题标题】:Cast a generic param to a specific type将泛型参数转换为特定类型
【发布时间】:2021-10-25 08:50:03
【问题描述】:

如果我有两个结构:

struct A {...}
struct B {...}

还有一个通用函数fn f<T>(param: T),我通过传递AB 的引用来调用它,该函数中有没有办法拥有这样的东西(伪代码):

if param is A {
    // do something with "param as A", like this:
    let a: A = (A) param;
    // ...
}

在 Java、C# 等语言中,我只需检查一个对象是否是 A 的实例,如果是,则将其转换为 A,如上例所示。我怎样才能在 Rust 中做这样的事情?我知道我可以在 trait 中加入一些特定于类型的逻辑,但我特别要求一种更简单、更直接的方式。

【问题讨论】:

标签: generics rust casting


【解决方案1】:

您可以完全按照您的要求使用 Any 特征的特征对象,例如

use std::any::Any;

#[derive(Debug)]
struct A;
#[derive(Debug)]
struct B;

fn foo(param: &dyn Any) {
    if let Some(a) = param.downcast_ref::<A>() {
        dbg!(a);
    }
    if let Some(b) = param.downcast_ref::<B>() {
        dbg!(b);
    }
}

但是,对于常见的用例,还有更多惯用、符合人体工程学和高效的解决方案。您在问题中提到在 AB 上实现一个共同特征,这是一种方法。另一种方法是定义一个枚举,其中包含您想要支持的所有类型的变体:

enum MyEnum {
    A(A),
    B(B),
}

fn bar(param: MyEnum) {
    match param {
        MyEnum::A(a) => { dbg!(a); },
        MyEnum::B(b) => { dbg!(b); },
    }
}

【讨论】:

  • 我认为这里有几点值得一提:(1)使用&amp;dyn Any会因为额外的间接性而对性能产生不利影响; (2) Java 和 C# 默认使用盒装类型,这就是为什么它们能够不费吹灰之力地做到这一点; (3) 依赖于运行时的类型检查会使您的抽象泄漏,并且通常表明您的抽象最初设计不佳。您无法将 Rust 与 Java 或 C# 进行比较,因为它们是完全不同的野兽。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多