gpt4 book ai didi

rust - 有什么方法可以转换为通用 T,其中 T 是任意特征类型?

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

我的问题标题有点模糊,但本质上我想达到以下目的:

  • struct Foo 实现了 BehaviourA 和 BehaviourB 以及 BehaviourC
  • struct Bar 实现 BehaviourA
  • Foo 和 Bar 都实现了一些内容特征
  • &Content 获取对行为的引用(如果已实现)。

从广义上讲,这可以通过强制 Content 明确了解 BehaviourA 等来实现,例如:

fn as_a(&self) -> Option<&BehaviourA>

但是,这需要 Content 类型明确知道所有行为类型,如果 Content 导出为 crate 中的 api,这是不可能的。

理想情况下,Content 应该有一个像这样的 api:

fn behaviour<T>(&self) -> Option<T> where T: Any;

可以在运行时调用为:

match content_item.behaviour::<&BehaviourA>() {
Some(x) => { ... },
None => {}
}

但是,我找不到任何方法来实现这个功能。

我最好的尝试是这样的:

fn behaviour<T>(&self) -> Option<T> where T: Any {
let own_type = TypeId::of::<T>();
if own_type == TypeId::of::<Behaviour>() { return Some(self as T); }
return None;
}

但这会导致:

src/foo.rs:21:62: 21:71 error: non-scalar cast: `&interface::test::Foo` as `T`
src/foo.rs:21 if own_type == TypeId::of::<Behaviour>() { return Some(self as T); }

我明白没有办法在运行时内省(introspection)对象的特征列表,但在这里我在实现中显式转换为已知类型;只是绑定(bind) T 并不总是满足。

有没有办法做到这一点,即使是不安全的?

显示错误的围栏示例如下:http://is.gd/fZNFA8

(注意。我看过 Can you restrict a generic to T where T is a trait implemented by Self?,但我的问题不同;简而言之,有没有办法在运行时生成特征引用,即使是不安全的?)

最佳答案

这里的根本问题是特征不是类型。当您说 &BehaviourA 时,您并不是指特征,而是指对象安全类型,它派生自特征。您需要做的是告诉 Rust T 不是类型,而是特征。

不幸的是,从 1.6 开始,仍然没有办法做到这一点。

我所知道的使这样的东西工作的唯一方法是显式地,a-la COM:您需要一个允许您请求“转换为对 X 的引用”的基本接口(interface)",然后在所有支持的 X 的每个具体类型上实现它。

如果您愿意研究不安全、困惑的代码,您可以通过一些宏 (playpen) 模糊地得到您想要的东西:

// Requires nightly compiler, since it depends on implementation details.
#![feature(raw)]

use std::any::TypeId;
use std::mem::transmute;
use std::raw::TraitObject;

macro_rules! qi {
($e:expr, $t:ty) => {
unsafe {
let iid = TypeId::of::<$t>();
let ptr = &$e;
match ptr.query_interface(&iid) {
Some(to) => {
let tmp: &$t = transmute(to);
Some(tmp)
},
None => None,
}
}
};
}

macro_rules! impl_unknown_for {
($base:ty: $($ints:ty),*) => {
unsafe impl Unknown for $base {
fn query_interface(&self, iid: &TypeId) -> Option<TraitObject> {
unsafe {
$(
if *iid == TypeId::of::<$ints>() {
let to = transmute::<&$ints, _>(self);
return Some(to);
}
)*
None
}
}
}
};
}

unsafe trait Unknown {
fn query_interface(&self, iid: &TypeId) -> Option<TraitObject>;
}

trait BehaviourA { fn a(&self); }
trait BehaviourB { fn b(&self); }
trait BehaviourC { fn c(&self); }

struct Thingy;

impl_unknown_for!(Thingy: BehaviourA, BehaviourC);

impl BehaviourA for Thingy {
fn a(&self) { println!("Thingy::a"); }
}

impl BehaviourC for Thingy {
fn c(&self) { println!("Thingy::c"); }
}

fn main() {
let obj: Box<Unknown> = Box::new(Thingy);
if let Some(ba) = qi!(obj, BehaviourA) { ba.a(); }
if let Some(bb) = qi!(obj, BehaviourB) { bb.b(); }
if let Some(bc) = qi!(obj, BehaviourC) { bc.c(); }
}

关于rust - 有什么方法可以转换为通用 T,其中 T 是任意特征类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33794138/

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