用在实现中决定类型的通用输出的枚举

huangapple go评论64阅读模式
英文:

Implementing enums with generic outputs with type decided in implementation

问题

I have this problem of wanting to create one struct with several fields, where one is an enum deciding how to handle many operations. Specifically, the enum decides what input and output types an important function has. I do not want the main structure to include an initialized structure of the input/output since they tend to change a lot and the values are not interesting for the main struct.

Given the setup:

struct Model<I, O> {
    name: String,
    model_type: ModelType,
    _data_format: PhantomData<(I, O)>,
    //... many other fields
}

enum ModelType {
    Onnx,
    DecisionTree,
}

impl ModelType {
   pub fn get_model<I, O>(self) -> Model<I, O> {
      match self {
         Self::Onnx => {
            Model<I, O> {
               name: "onnx".into(),
               model_type: Self::Onnx,
               PhantomData::<(I, O)> //  &lt;--- Cant do it like this, what should be done here?? without initializing the given structures.
            }
         },
         //.. other models
     }
   }
}

struct OnnxInput {
    matrix: Vec<Vec<f64>
}

struct DtInput {
    color: f32,
    size: f32,
    //... more... 
}

impl<I, O> Model<I, O> {
    pub fn score(&self, input: I) -> O {
        
        self.model_type.score::<I>(input)
    }
    
}

impl ModelType {
    pub fn score<I>(&self, input: I) -> O
}
英文:

I have this problem of wanting to create one struct with several fields, where one is an enum deciding the how to handle many operations. Specifically, the enum decides what input and output types an important function has. I do not want the main structure to include. an initialized structure of theinput/output since they tend to change a lot and the values are not interesting for the main struct.

Given the setup:

struct Model&lt;I,O&gt; {
    name: String,
    model_type: ModelType
    _data_format: PhantomData::&lt;(I,O)&gt;
    //... many other fields
}

enum ModelType{
    Onnx,
    DecisiomTree,
}

impl ModelType{
   pub fn get_model&lt;I,O&gt;(self) -&gt; Model&lt;I,O&gt;{
      match self {
         Self::Onnx =&gt; {
            Model&lt;I,O&gt; {
               name: &quot;onnx&quot;.into(),
               model_type: Self::Onnx,
               PhantomData::&lt;(OnnxInput,OnnxOutput)&gt; //  &lt;--- Cant do it like this, what should be done here?? without initializing the given structures.
            }
         },
         //.. other models
     }
   }
}

struct OnnxInput {
    matrix: Vec&lt;Vec&lt;f64&gt;&gt;
}

struct DtInput {
    color: f32,
    size: f32,
    //... more... 
}

impl&lt;I,O&gt; Model&lt;I,O&gt; {
    pub fn score(&amp;self, input: I) -&gt; O{
        
        self.model_type.score::&lt;I&gt;(input)
    }
    
}

impl ModelType{
    pub fn score&lt;I&gt;(&amp;self, input: I) -&gt; O
}

答案1

得分: 1

以下是您要翻译的内容:

I think what you want is achievable with unit structs implementing a trait, instead of a ModelType enum, like this:

use std::marker::PhantomData;

trait ModelScore {
    type Input;
    type Output;
    
    fn score(i: Self::Input) -> Self::Output;
}

struct Model<T: ModelScore> {
    marker: PhantomData<T>,
}

impl<T: ModelScore> Model<T> {
    fn new() -> Self {
        Self {
            marker: PhantomData,
        }
    }
    
    fn score(&self, i: T::Input) -> T::Output {
        T::score(i)
    }
}

struct Onnx;

struct OnnxInput;

#[derive(PartialEq, Debug)]
struct OnnxOutput;

struct DecisionTree;

struct DecisionTreeInput;

#[derive(PartialEq, Debug)]
struct DecisionTreeOutput;

impl ModelScore for Onnx {
    type Input = OnnxInput;
    type Output = OnnxOutput;
    
    fn score(_: Self::Input) -> Self::Output {
        OnnxOutput
    }
}

impl ModelScore for DecisionTree {
    type Input = DecisionTreeInput;
    type Output = DecisionTreeOutput;
    
    fn score(_: Self::Input) -> Self::Output {
        DecisionTreeOutput
    }
}

fn main() {
    let m1: Model<Onnx> = Model::new();
    let m2: Model<DecisionTree> = Model::new();
    
    assert_eq!(m1.score(OnnxInput), OnnxOutput);
    assert_eq!(m2.score(DecisionTreeInput), DecisionTreeOutput);
}

Playground.

Instead of ModelType we now have a trait ModelScore with associated types Input and Output. The variants of ModelType were replaced by the unit structs Onnx and DecisionTree, which both implement ModelScore. That allows us to define our Model instances as seen in the main function with let m1: Model<Onnx> = Model::new(). Your input and output types are known to the compiler but not initialized, as was your requirement.

英文:

I think what you want is achievable with unit structs implementing a trait, instead of a ModelType enum, like this:

use std::marker::PhantomData;

trait ModelScore {
    type Input;
    type Output;
    
    fn score(i: Self::Input) -&gt; Self::Output;
}

struct Model&lt;T: ModelScore&gt; {
    marker: PhantomData&lt;T&gt;,
}

impl&lt;T: ModelScore&gt; Model&lt;T&gt; {
    fn new() -&gt; Self {
        Self {
            marker: PhantomData,
        }
    }
    
    fn score(&amp;self, i: T::Input) -&gt; T::Output {
        T::score(i)
    }
}


struct Onnx;

struct OnnxInput;

#[derive(PartialEq, Debug)]
struct OnnxOutput;

struct DecisionTree;

struct DecisionTreeInput;

#[derive(PartialEq, Debug)]
struct DecisionTreeOutput;

impl ModelScore for Onnx {
    type Input = OnnxInput;
    type Output = OnnxOutput;
    
    fn score(_: Self::Input) -&gt; Self::Output {
        OnnxOutput
    }
}

impl ModelScore for DecisionTree {
    type Input = DecisionTreeInput;
    type Output = DecisionTreeOutput;
    
    fn score(_: Self::Input) -&gt; Self::Output {
        DecisionTreeOutput
    }
}

fn main() {
    let m1: Model&lt;Onnx&gt; = Model::new();
    let m2: Model&lt;DecisionTree&gt; = Model::new();
    
    assert_eq!(m1.score(OnnxInput), OnnxOutput);
    assert_eq!(m2.score(DecisionTreeInput), DecisionTreeOutput);
}

Playground.

Instead of ModelType we now have a trait ModelScore with associated types Input and Output. The variants of ModelType were replaced by the unit structs Onnx and DecisionTree, which both implement ModelScore. That allows us to define our Model instances as seen in the main function with let m1: Model&lt;Onnx&gt; = Model::new(). Your input and output types are known to the compiler but not initialized, as was your requirement.

huangapple
  • 本文由 发表于 2023年3月7日 00:37:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定