有没有办法打开 return 类型,以便编译器知道 return 类型和匹配的类型相同?
Is there a way to switch on return types so that the compiler knows that the return type and matched type are the same?
如何避免在下面的代码中使用不安全的代码?它意味着成为实体组件系统库的一部分。更一般地说,有没有一种方法可以在 Rust 中打开 return 类型,编译器会在块内知道 return 类型和匹配类型相同?
use std::any::{Any, TypeId};
use std::mem;
#[derive(Debug)] struct Health(f64);
#[derive(Debug)] struct Position([f64; 3]);
trait Entity {
fn get<'a, T: Any>(&self) -> Option<&'a T>;
}
#[derive(Debug)]
struct Pig {
health: Health,
position: Position,
}
impl Entity for Pig {
fn get<'a, T: Any>(&self) -> Option<&'a T> {
if TypeId::of::<T>() == TypeId::of::<Health>() {
Some(unsafe {mem::transmute(&self.health)})
} else if TypeId::of::<T>() == TypeId::of::<Position>() {
Some(unsafe {mem::transmute(&self.position)})
} else { None }
}
}
fn main() {
let waddles = Pig {
health: Health(2.0),
position: Position([1.0, 2.0, 3.0]),
};
println!("Waddles' Health: {:?}", waddles.get::<Health>());
}
你可以这样做:
fn get<T: Any>(&self) -> Option<&T> {
if let Some(health) = Any::downcast_ref::<T>(&self.health) {
Some(&health)
}
else if let Some(position) = Any::downcast_ref::<T>(&self.position) {
Some(&position)
} else {
None
}
}
请注意,我还从函数头中删除了显式生命周期(也在特征定义中)。生命周期省略在这种情况下有效,因为输出生命周期绑定到输入生命周期 (self
)。
上面的代码比较冗长,有很多重复代码。因此,为它编写一个简单的宏可能会有用:
macro_rules! entity_match {
($self_:ident; $($entity:ident),*) => {{
$(if let Some(inner) = Any::downcast_ref::<T>(&$self_.$entity) {
return Some(&inner);
})*
None
}}
}
impl Entity for Pig {
fn get<T: Any>(&self) -> Option<&T> {
entity_match!(self; health, position)
}
}
注意一点:我认为在这里使用编译器插件会非常好,将一些结构成员标记为结构定义中的实体。
如何避免在下面的代码中使用不安全的代码?它意味着成为实体组件系统库的一部分。更一般地说,有没有一种方法可以在 Rust 中打开 return 类型,编译器会在块内知道 return 类型和匹配类型相同?
use std::any::{Any, TypeId};
use std::mem;
#[derive(Debug)] struct Health(f64);
#[derive(Debug)] struct Position([f64; 3]);
trait Entity {
fn get<'a, T: Any>(&self) -> Option<&'a T>;
}
#[derive(Debug)]
struct Pig {
health: Health,
position: Position,
}
impl Entity for Pig {
fn get<'a, T: Any>(&self) -> Option<&'a T> {
if TypeId::of::<T>() == TypeId::of::<Health>() {
Some(unsafe {mem::transmute(&self.health)})
} else if TypeId::of::<T>() == TypeId::of::<Position>() {
Some(unsafe {mem::transmute(&self.position)})
} else { None }
}
}
fn main() {
let waddles = Pig {
health: Health(2.0),
position: Position([1.0, 2.0, 3.0]),
};
println!("Waddles' Health: {:?}", waddles.get::<Health>());
}
你可以这样做:
fn get<T: Any>(&self) -> Option<&T> {
if let Some(health) = Any::downcast_ref::<T>(&self.health) {
Some(&health)
}
else if let Some(position) = Any::downcast_ref::<T>(&self.position) {
Some(&position)
} else {
None
}
}
请注意,我还从函数头中删除了显式生命周期(也在特征定义中)。生命周期省略在这种情况下有效,因为输出生命周期绑定到输入生命周期 (self
)。
上面的代码比较冗长,有很多重复代码。因此,为它编写一个简单的宏可能会有用:
macro_rules! entity_match {
($self_:ident; $($entity:ident),*) => {{
$(if let Some(inner) = Any::downcast_ref::<T>(&$self_.$entity) {
return Some(&inner);
})*
None
}}
}
impl Entity for Pig {
fn get<T: Any>(&self) -> Option<&T> {
entity_match!(self; health, position)
}
}
注意一点:我认为在这里使用编译器插件会非常好,将一些结构成员标记为结构定义中的实体。