我有一个结构,确切地说,存在两个版本。也就是说,该结构具有一个属性,该属性描述了它是哪个版本(具有两个变体的bool
或enum
)作为构造函数中的参数传递。结构在编译时就知道哪个版本。在该结构的大多数方法中,根据属性的值,调用了相应的方法(在此结构的属性上)。这样会在整个结构的impl
中产生许多if语句。
我考虑过将所有代码都移到一个特征中,但这似乎不合适:动态调度不是必需的,几乎所有方法都没有self
参数,所有属性的setters / getters将是需要。我仍然剩下两个相同的结构声明。而且,该特征没有描述其他结构应实现的任何一般行为。
如果我可以创建此结构的通用版本并实例化这两个版本之一,那将是理想的选择。由于缺少更好的词,我只能使用一种具有不同行为的方法来构造我的结构的两个“子类型”。这样的事情有可能吗?
它关系到性能至关重要的应用程序,并且此结构上的方法将被多次调用。不是为了维护性,我只是复制所有代码。我将创建两个几乎相同的结构,其中在方法内部,有一个版本的外部方法被调用,或者另一个版本。
答案 0 :(得分:2)
将a trait用于具有多种实现的行为。您可以使用多种方式进行组合,这是一种:
use std::marker::PhantomData;
trait Core {
fn print();
}
#[derive(Debug, Default)]
struct PrintA;
impl Core for PrintA {
fn print() {
print!("a")
}
}
#[derive(Debug, Default)]
struct PrintB;
impl Core for PrintB {
fn print() {
print!("b")
}
}
#[derive(Debug, Default)]
struct Thing<C>(PhantomData<C>);
impl<C: Core> Thing<C> {
fn common() {
print!(">");
C::print();
println!("<")
}
}
fn main() {
Thing::<PrintA>::common();
Thing::<PrintB>::common();
}
或另一个:
trait Core {
fn select<'a>(left: &'a i32, right: &'a i32) -> &'a i32;
}
#[derive(Debug, Default)]
struct Left;
impl Core for Left {
fn select<'a>(left: &'a i32, _right: &'a i32) -> &'a i32 {
left
}
}
#[derive(Debug, Default)]
struct Right;
impl Core for Right {
fn select<'a>(_left: &'a i32, right: &'a i32) -> &'a i32 {
right
}
}
#[derive(Debug, Default)]
struct Thing<C> {
kind: C,
left: i32,
right: i32,
}
impl Thing<Left> {
fn new_left(left: i32, right: i32) -> Self {
Self {
left,
right,
kind: Left,
}
}
}
impl Thing<Right> {
fn new_right(left: i32, right: i32) -> Self {
Self {
left,
right,
kind: Right,
}
}
}
impl<C: Core> Thing<C> {
fn add_one(&self) -> i32 {
self.select() + 1
}
fn select(&self) -> &i32 {
C::select(&self.left, &self.right)
}
}
pub fn l() -> i32 {
let l = Thing::new_left(100, 200);
l.add_one()
}
pub fn r() -> i32 {
let r = Thing::new_right(100, 200);
r.add_one()
}
值得注意的是,最后一个示例编译为以下LLVM IR:
define i32 @_playground_l() {
start:
ret i32 101
}
define i32 @_playground_r() {
start:
ret i32 201
}
我考虑过将所有代码都转换为特征,但这似乎不合适:动态分配不是必需的,几乎所有方法都没有
self
参数
self
这不是出于可维护性,我只复制所有代码
如果无法处理特质,听起来像macros合适的地方。