rust - 如何将泛型 T 的实例转换为 Rust 中的具体实例?

标签 rust

我正在尝试实现这种模式:

use std::any::Any;
use std::fmt::Debug;

trait CommandHandler<TCommand> {
    fn execute(&self, data: TCommand);
}

#[derive(Debug)]
struct FooCommand {}

struct FooCommandHandler {}

impl CommandHandler<FooCommand> for FooCommandHandler {
    fn execute(&self, data: FooCommand) {
        println!("Foo");
    }
}

#[derive(Debug)]
struct BarCommand {}

struct BarCommandHandler {}

impl CommandHandler<BarCommand> for BarCommandHandler {
    fn execute(&self, data: BarCommand) {
        println!("Bar");
    }
}

fn execute<T>(command: T)
where
    T: Any + Debug,
{
    println!("Command: {:?}", command);
    match (&command as &Any).downcast_ref::<FooCommand>() {
        Some(c) => (FooCommandHandler {}).execute(c),
        None => {}
    };
    match (&command as &Any).downcast_ref::<BarCommand>() {
        Some(c) => (BarCommandHandler {}).execute(c),
        None => {}
    };
}

fn main() {
    (FooCommandHandler {}).execute(FooCommand {});
    (BarCommandHandler {}).execute(BarCommand {});
    execute(FooCommand {});
    execute(BarCommand {});
}

这行不通:

error[E0308]: mismatched types
  --> src/main.rs:37:51
   |
37 |         Some(c) => (FooCommandHandler {}).execute(c),
   |                                                   ^ expected struct `FooCommand`, found &FooCommand
   |
   = note: expected type `FooCommand`
              found type `&FooCommand`

error[E0308]: mismatched types
  --> src/main.rs:41:51
   |
41 |         Some(c) => (BarCommandHandler {}).execute(c),
   |                                                   ^ expected struct `BarCommand`, found &BarCommand
   |
   = note: expected type `BarCommand`
              found type `&BarCommand`

我如何实现 execute()保留以下要求的方法:

  • 类型XCommand应该是完全天真的XCommandHandler是执行它的。
  • CommandHandler<X> 的多个实现可能存在。
  • 命令处理程序接收(并使用)具体的命令实例,而不是对它的引用(使得重复发送命令成为不可能)。

本质上,我有一个通用函数 fn foo<T>(v: T)我想 dispatch 到一些具体的功能fn foo1(v: Foo) , fn foo2(v: Bar) ;我该怎么做?

transmute唯一的选择?

请注意,这与 Any::downcast_ref 不同确实如此,它返回一个 &Foo , 不是 Foo来自通用值 v.

最佳答案

你需要通过Box,像这样:

fn execute<T>(command: T)
where
    T: Any + Debug,
{
    println!("Command: {:?}", command);
    let any: Box<Any> = Box::new(command);

    let any = match any.downcast() {
        Ok(c) => return (FooCommandHandler {}).execute(*c),
        Err(any) => any,
    };

    let any = match any.downcast() {
        Ok(c) => return (BarCommandHandler {}).execute(*c),
        Err(any) => any,
    };

    let _ = any; // avoid unused variable error
    panic!("could not downcast command");
}

“但是我不想使用Box!”

只需使用 Box

“但它是一个分配!我已经测量了上面的代码并毫无疑问地证明它是一个瓶颈!”

什么? 真的吗?

“否则你无法证明。”

很好。但我保证这在所有情况下都有效。这正在踏入“自爆”的领域。不要这样做,除非你知道你需要:

fn execute<T>(command: T)
where
    T: Any + Debug,
{
    use std::any::TypeId;
    use std::mem;

    println!("Command: {:?}", command);

    macro_rules! do_cast {
            ($t:ty, $h:expr) => {
                if TypeId::of::<T>() == TypeId::of::<$t>() {
                    let casted: $t = mem::transmute_copy(&command);
                    mem::forget(command); // we CANNOT let command drop.
                    $h.execute(casted);
                    return;
                }
            };
        }

    unsafe {
        do_cast!(FooCommand, FooCommandHandler {});
        do_cast!(BarCommand, BarCommandHandler {});
    }

    panic!("could not downcast command");
}

关于rust - 如何将泛型 T 的实例转换为 Rust 中的具体实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48921861/

相关文章:

rust - 将jni::sys::JNIEnv转换为ffi中定义的JNINativeInterface

multithreading - 如何可靠地清理执行阻塞 IO 的 Rust 线​​程?

dynamic - 如何在actix_web/rust的http响应中流式传输非静态字节?

winapi - 设置 Windows 控制台的文本颜色未按预期工作

for-loop - 将嵌套的 for 循环转换为迭代器

rust - 为什么结构实例化的花括号没有定义作用域?

indexing - 如何将范围作为 Rust 中的变量?

python - Rust:逐个字符打印出字符串

rust - 生命周期参数化结构上方法的正确类型是什么?

string - 如何从标准输入中读取单个字符串?