英文:
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)> // <--- 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<I,O> {
name: String,
model_type: ModelType
_data_format: PhantomData::<(I,O)>
//... many other fields
}
enum ModelType{
Onnx,
DecisiomTree,
}
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::<(OnnxInput,OnnxOutput)> // <--- 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
}
答案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);
}
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) -> 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);
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论