gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:59:35 26 4
gpt4 key购买 nike

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

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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com