generics - 使用类似泛型构造的子类型

标签 generics types rust

我有一个结构,其中恰好存在两个版本。也就是说,该结构有一个描述它是哪个版本的属性(boolenum 有两个变体),该属性作为参数传递到构造函数中。该结构将具有哪个版本在编译时是已知的。在此结构的大多数方法中,将调用相应的方法(在此结构的属性上),具体取决于属性的值。这导致在该结构的 impl 中出现许多 if 语句。

我考虑过将所有代码移动到特征中,但这似乎不合适:动态分派(dispatch)不是必需的,几乎所有方法都没有 self 参数和所有的 setters/getters属性将是必需的。我仍然会留下两个相同的结构声明。此外,该特征并未描述其他结构应实现的任何通用行为。

如果我可以改为创建此结构的通用版本,并实例化两个版本之一,那就太理想了。由于缺乏更好的词,我的结构的两个“子类型”只有一个具有不同行为的方法。这样的事情可能吗?

它涉及一个性能关键的应用程序,这个结构上的方法将被多次调用。这不是为了可维护性,我只是复制所有代码。我会创建两个几乎相同的结构,在方法内部,要么调用一个版本的外部方法,要么调用另一个。

最佳答案

使用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
}

I considered moving all of the code into a trait, but this didn't seem appropriate: dynamic dispatch is not necessary, almost all methods will not have the self parameter

  • 特性并不意味着动态调度。参见单态化
  • trait 方法不需要self

It it wasn't for maintainability, I would just copy all code

听起来像一个地方 macros如果您不能处理特征,可能是合适的。

关于generics - 使用类似泛型构造的子类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53242628/

相关文章:

rust - 如何向/从 NonNull<Opaque> 添加/减去偏移量?

java - 如何在泛型类中定义具体类型构造函数

arrays - 具有通用项的 Swift 数组扩展

c# - 如何将泛型类型参数用作声明为具有类型约束的接口(interface)的属性的类型参数?

java - jackson .当值从泛型类获取时出现 ClassCastException

c++ - 到处使用 std::size_t 是一种好习惯吗?

haskell - 如何限制元组?

c++ - 如何在不使用开关的情况下随机选择一个类进行实例化?

rust - 如何在具有空值的结构中设置字段?

error-handling - Rust:从标准输入读取和映射行并处理不同的错误类型