// ===== library code: =====
trait Sate { // Or in C++ imagine this is a class containing only pure virtuals.
fn ready(&mut self, ..);
fn terminate(&mut self, ..);
fn timeout(&mut self, .. );
fn ....; // a few more functions
fn as_any(&mut self) -> &mut Any; // for downcasting in Rust; not necessary in C++
}
states: HashMap<u32, Rc<RefCell<State>>>; // Or in C++ just a map of numbers to shared-ptr of State
fn event_loop_on_some_trigger(trigger_for: u32, trigger: Blah) {
let state = states[trigger_for];
if trigger == for_timeout { state.borrow_mut().timeout(...) }
else if trigger = for_readiness { state.borrow_mut().timeout(...) }
...
}
//==== User Code: ====
struct Type0 { ... }
impl State for Type0 { /* provide concrete impls */ } // In C++ this would be inheritance for Type0
struct Type1 { ... }
impl State for Type1 { /* provide concrete impls */ } // In C++ this would be inheritance for Type1
// ... etc.
我正在使用该库,并且一切正常。但是现在有一些类型必须要做
超出上述State
特性的一些特定工作。所以我逐渐显得
在设计中遇到了“表达问题”。我不控制图书馆提供的
特征和事件循环,即使我做到了,我也不会添加2或3个额外的功能
在那里,因为它感觉不对,因为它将仅用于某些具体类型,并且
太偶然了。
我另外拥有的是HashMap<u32, SomeDetail>
这样的用户代码中的Map,
对应于上面的事件循环线程堆栈中的映射。因此,如果我需要执行特殊
我可以对一种类型的操作进行操作以获取状态的u32
值(通过分析SomeDetail
或其他方式),从事件循环中的地图获取状态,并将其向下转换为要调用的类型
特殊功能之一。
目前在C ++中,我可能会使用static_cast<>
,因为我确定它是什么类型
(除非ID或它的分配的保值中有问题,否则
程序中的逻辑错误)。在Rust中,我被迫使用downcast_mut
(在C ++中为dynamic_cast
),
我同意(到目前为止,我从未收到任何运行时错误,表明逻辑是
声音和static_cast
是否可以安全使用也可以)。
现在我的问题是,我读到铸造是不良设计等。所以我在想我该怎么办?
在这里做了不同的事情。一种想法是将弱(或强如果我们不在乎)引用存储在
我的用户代码中有地图。因此,虽然事件循环使用地图,但它必须触发一些
State
的功能,我会随时使用地图来获取具体类型
并在其上调用函数。但是,由于我的代码不在eventloop线程之外,
在州上使用Mutex,这在99%的时间内是无用的,因为大多数情况下
eventloop调用它,并按照代码的类型进行操作。
<u32, ConcreteTypeReferences>
的映射,以便在极少数情况下我想与具体类型进行交互时可以将请求发布到事件循环中,并且它们可以继续生存而无需互斥或原子-referece-counted对象(在Rust Rc中是非原子引用计数的smart-ptr,我不知道C ++中是否有等效对象)最后一个选项,也有一部分是第一个,要求我可以访问该代码-因此,更多的是愿望清单,但只是想知道如果是这样的话,那将是什么建议。如果没有(2),dynamic_cast
似乎是唯一可行的解决方案?