Generics 如何创建可以接受任何参数的闭包向量?
这是我当前的代码:Generics 如何创建可以接受任何参数的闭包向量?,generics,vector,rust,Generics,Vector,Rust,这是我当前的代码: pub struct EventEmitter { pub listeners: Vec<Arc<dyn Fn()>>, } 我认为不可能直接这样做,但是如果您的类型t可以序列化,那么这里有一种方法。将侦听器设置为Vec,插入此Vec时,传递一个lambda,该lambda将字符串转换为T,并调用实际的侦听器函数。以下是我的意思的工作代码: 使用std::sync::Arc; 结构事件发射器{ 听众:Vec,, } impl事件发射器{ 发布
pub struct EventEmitter {
pub listeners: Vec<Arc<dyn Fn()>>,
}
我认为不可能直接这样做,但是如果您的类型t可以序列化,那么这里有一种方法。将
侦听器
设置为Vec
,插入此Vec时,传递一个lambda,该lambda将字符串转换为T,并调用实际的侦听器函数。以下是我的意思的工作代码:
使用std::sync::Arc;
结构事件发射器{
听众:Vec,,
}
impl事件发射器{
发布fn添加侦听器(&mut self,侦听器:Arc)
哪里
T:std::str::FromStr,//因此可以将's'转换为'T'类型。
::Err:std::fmt::Debug,//以便可以打印'e'。
T:'静态,//参见https://stackoverflow.com/a/29740792/8111265
{
self.listeners.push(Arc::new(move | s |{
匹配s.parse::(){
Ok(t)=>侦听器(t),
Err(e)=>println!(“哎呀!我们无法将{:?}转换为t类型,因为{:?}”,s,e),
};
}));
}
发布fn通知(&self,s:&str){
对于self.listeners.iter()中的侦听器{
侦听器(s.to_string());
}
}
}
#[测试]
fn测试事件发射器(){
让mute=EventEmitter{listeners:vec![]};
//i32实现'std::str::FromStr'。
e、 添加|u侦听器(Arc::new(|x:i32|){
println!(“在i32侦听器中获得{:?}”,x);
}));
//std::net::IpAddr实现“std::str::FromStr”。
e、 添加侦听器(Arc::new(| ip_addr:std::net::IpAddr |{
println!(“在IpAddr侦听器中获得{:?}”,ip_addr);
}));
//这行打印:
//i32侦听器中有42个
//哎呀!由于AddrParseError(())的原因,我们无法将“42”转换为t类型
e、 通知(“42”);
//这行打印:
//哎呀!由于ParseInteror{kind:InvalidDigit},我们无法将“127.0.0.1”转换为t类型
//在IpAddr侦听器中获得了V4(127.0.0.1)
e、 通知(“127.0.0.1”);
}
这个想法可以再细化一点:也许不需要一些弧
s,也许有一个比String更好的“base”类型(可能这可以用于与serde一起工作的任何类型),您可以使用&str
而不是String本身
既然您询问了如何使用serde,下面是一个示例:
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct PointInts {
x: i32,
y: i32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct PointFloats {
x: f32,
y: f32,
}
struct EventEmitter {
listeners: Vec<Arc<dyn Fn(&[u8])>>,
}
impl EventEmitter {
pub fn add_listener<T>(&mut self, listener: Arc<dyn Fn(T)>)
where
T: serde::de::DeserializeOwned,
T: 'static, // See https://stackoverflow.com/a/29740792/8111265
{
self.listeners.push(Arc::new(move |bytes| {
match bincode::deserialize(bytes) {
Ok(t) => listener(t),
Err(e) => println!(
"Oops! we couldn't convert the bytes {:?} to type T due to {:?}",
bytes, e
),
};
}));
}
pub fn notify<T>(&self, obj: T)
where
T: serde::Serialize,
{
let bytes = bincode::serialize(&obj).unwrap();
for listener in self.listeners.iter() {
listener(&bytes);
}
}
}
#[test]
fn test_event_emitter() {
let mut e = EventEmitter { listeners: vec![] };
// PoinitInts implements Serialize and Deserialize.
e.add_listener(Arc::new(|p: PointInts| {
println!("Got {:?} in PointInts listener", p);
}));
// PointFloats implements Serialize and Deserialize.
e.add_listener(Arc::new(|p: PointFloats| {
println!("Got {:?} in PointFloats listener", p);
}));
// This line prints:
// Got PointInts { x: 42, y: 999 } in PointInts listener
// Got PointFloats { x: 0.000000000000000000000000000000000000000000059, y: 0.0000000000000000000000000000000000000000014 } in PointFloats listener
e.notify(PointInts { x: 42, y: 999 });
// This line prints:
// Got PointInts { x: 1109917696, y: 1120327434 } in PointInts listener
// Got PointFloats { x: 42.0, y: 99.42 } in PointFloats listener
e.notify(PointFloats { x: 42.0, y: 99.420 });
}
使用serde::{反序列化,序列化};
使用std::sync::Arc;
#[派生(序列化、反序列化、PartialEq、调试)]
结构指针{
x:i32,
y:i32,
}
#[派生(序列化、反序列化、PartialEq、调试)]
结构点浮动{
x:f32,
y:f32,
}
结构事件发射器{
听众:Vec,,
}
impl事件发射器{
发布fn添加侦听器(&mut self,侦听器:Arc)
哪里
T:serde::de::反序列化拥有,
T:'静态,//参见https://stackoverflow.com/a/29740792/8111265
{
self.listeners.push(Arc::new(move | bytes |{
匹配bincode::反序列化(字节){
Ok(t)=>侦听器(t),
错误(e)=>println(
“哎呀!由于{:?},我们无法将字节{:?}转换为类型t”,
字节,e
),
};
}));
}
发布fn通知(&self,obj:T)
哪里
T:serde::序列化,
{
让bytes=bincode::序列化(&obj).unwrap();
对于self.listeners.iter()中的侦听器{
侦听器(&字节);
}
}
}
#[测试]
fn测试事件发射器(){
让mute=EventEmitter{listeners:vec![]};
//POINTENTS实现序列化和反序列化。
e、 添加侦听器(Arc::new(| p:PointInts |{
println!(“在PointInts侦听器中获得{:?}”,p);
}));
//PointFloats实现序列化和反序列化。
e、 添加侦听器(Arc::new(| p:PointFloats |{
println!(“在PointFloats侦听器中获得{:?}”,p);
}));
//这行打印:
//在PointInts侦听器中获取了PointInts{x:42,y:999}
//在PointFloats侦听器中获取了PointFloats{x:0.000000000000000000000000000000000000059,y:0.0000000000000000000000000000000000000000000000014}
e、 通知(PointInts{x:42,y:999});
//这行打印:
//在PointInts侦听器中获取了PointInts{x:1109917696,y:1120327434}
//在PointFloats侦听器中获得了PointFloats{x:42.0,y:99.42}
e、 通知(点浮动{x:42.0,y:99.420});
}
请注意,如果字节可以转换为给定的请求结构,则
bincode::deserialize
将返回Ok(41;
,这就是为什么您会看到上面奇怪的值(可能有一种方法可以添加类型标记,以便“错误”结构不会被反序列化).您可以在某种程度上使用Any
特性模拟动态键入。这个特性由大多数类型实现,类型为Any
的特性对象可以向下转换为具体类型
use std::any::Any;
use std::sync::Arc;
pub struct EventEmitter {
pub listeners: Vec<Arc<dyn Fn(Box<dyn Any>)>>,
}
fn wrap<F, T>(f: F) -> impl Fn(Box<dyn Any>)
where
F: Fn(T),
T: Any,
{
move |x| f(*x.downcast::<T>().unwrap())
}
fn main() {
let first = |foo: i32| {
let _ = foo + 1;
};
let second = |bar: String| println!("{}", bar);
let mut emitter = EventEmitter {
listeners: Vec::new(),
};
emitter.listeners.push(Arc::new(wrap(first)));
emitter.listeners.push(Arc::new(wrap(second)));
}
传递错误的类型将导致恐慌,因为我们对downcast()
方法调用的结果使用了unwrap()
。根据您的需要,您可以将错误返回给调用者或以不同的方式处理它
这仍然留下了一个悬而未决的问题,您将如何实际使用它。您必须记住向量中的哪个索引对应于什么参数类型才能实际调用这些函数。我不知道您的用例,但几乎可以肯定,使用自定义特性和动态调度有更好的解决方案。我想到的最健壮的方法是使用原始指针和一些不安全的代码 将封口包裹在另一个封口内:
let callback = |value: &str| {};
let wrapped_callback = move |raw_pointer: usize| {
unsafe {
let value: T = &*(raw_pointer as *const T);
callback(value);
}
}
然后,每次我们要调用回调时,首先将值转换为原始指针:
pub fn<T> notify(&self, value: T) {
let raw_pointer = &value as *const T as usize;
for callback is self.listeners.iter() {
wrapped_callback(raw_pointer.clone());
}
}
pub fn notify(&self,值:T){
让原始指针=&值为*常数为usize;
因为回调是self.listeners.iter(){
包装的_回调(raw_pointer.clone());
}
}
然后侦听器类型变为:
pub listeners: Vec<Arc<dyn Fn(usize)>>,
发布侦听器:Vec,
这使我们能够拥有一个数组,该数组可以接收任意数量的函数,这些函数具有不同的类型作为其参数
发布的其他解决方案不起作用
let callback = |value: &str| {};
let wrapped_callback = move |raw_pointer: usize| {
unsafe {
let value: T = &*(raw_pointer as *const T);
callback(value);
}
}
pub fn<T> notify(&self, value: T) {
let raw_pointer = &value as *const T as usize;
for callback is self.listeners.iter() {
wrapped_callback(raw_pointer.clone());
}
}
pub listeners: Vec<Arc<dyn Fn(usize)>>,