繁体   English   中英

如何有效地处理 rust 中不同具体类型的泛型类型?

[英]How to handle generic types with different concrete types in rust efficiently?

主要目标是实现一个计算图,它处理带有值的节点和带有运算符的节点(想想简单的算术运算符,如加法、减法、乘法等)。 一个算子节点最多可以占用两个值节点,并“产生”一个结果值节点。

到目前为止,我使用枚举来区分值和操作符节点:

pub enum Node<'a, T> where T : Copy + Clone {
    Value(ValueNode<'a, T>),
    Operator(OperatorNode)
}

pub struct ValueNode<'a, T> {
   id: usize, 
   value_object : &'a dyn ValueType<T>
}

更新Node::Value包含一个结构,它本身包含对特征 object ValueType的引用,该特征由各种具体类型实现。

但问题来了。 在编译期间,泛型类型将被省略,并由实际类型替换。 泛型T也在整个计算图中传播(显然):

pub struct ComputationGraph<T> where T : Copy + Clone {
    nodes: Vec<Node<T>>
}

这实际上将ComputeGraph的使用限制为一个特定的ValueType

此外,通用类型T不能是Sized ,因为值节点可以是由 rust 不可用的不同后端处理的 opqaue 类型(想想通过 FFI 提供的 C opqaue 类型)。

这个问题的一个可能的解决方案是引入一个额外的枚举类型,它“镜像”上面提到的 valuetype 特征的具体实现。 这种方法与枚举调度类似。

有什么我没有想到要使用ValueType的多个实现的吗?

更新

我想要实现的是以下代码:

pub struct Scalar<T> where T : Copy + Clone{
    data : T
}

fn main() {
   let cg = ComputeGraph::new();

   // a new scalar type. doesn't have to be a tuple struct   
   let a = Scalar::new::<f32>(1.0);

   let b_size = 32; 
   let b = Container::new::<opaque_type>(32);

   let op = OperatorAdd::new();

   // cg.insert_operator_node constructs four nodes: 3 value nodes  
   // and one operator nodes internally. 
   let result = cg.insert_operator_node::<Container>(&op, &a, &b);

} 

更新

ValueType<T>看起来像这样

pub trait ValueType<T> {
    fn get_size(&self) -> usize;
    fn get_value(&self) -> T;
}

更新

为了进一步提高我的问题的清晰度,请考虑一个由 OpenCL 支持的小型 BLAS 库。 memory 管理和设备交互对用户应该是透明的。 Matrix 类型在 OpenCL 设备上分配空间,类型为原始类型缓冲区,适当的调用将返回指向 memory 的特定区域的指针。 考虑一个将通过标量类型缩放矩阵的操作,它由原始值表示。 (指向)缓冲区和标量都可以传递给 kernel function。 回到ComputeGraph ,似乎很明显,所有 BLAS 操作都形成某种类型的计算图,可以简化为指令的线性列表(在这里考虑设置 kernel arguments,分配缓冲区,将 Z50484C19F1AFDAF38821AFDAF33 入队存储结果ETC... )。 说了这么多,计算图需要能够存储各种类型的值节点。

与往常一样,问题中提出的问题的答案是显而易见的。 该图需要一种泛型类型(具有特征边界)。 正如问题中已经概述的那样,使用枚举来“聚集”各种子类型是解决方案。

一个例子来说明解决方案。 考虑以下“子类型”:

struct Buffer<T> {
   // fields
}

struct Scalar<T> {
   // fields
}

struct Kernel {
   // fields
}

包含类型的值可以打包到一个枚举中:

enum MemType {
   Buffer(Buffer<f32>);
   Scalar(Scalar<f32>);
   // more enum variants ..
}

现在MemTypeKernel现在也可以打包在一个枚举中

enum Node {
   Value(MemType);
   Operator(Kernel);
}

Node现在可以用作图中节点/顶点的主要类型。 该解决方案可能不是很优雅,但现在可以解决问题。 也许将来可能会进行一些代码重组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM