英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论