gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 08:26:46 25 4
gpt4 key购买 nike

我有一个结构,其中恰好存在两个版本。也就是说,该结构有一个描述它是哪个版本的属性(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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com