问题
I'm writing a program which parses a number of files. These files can fall into a number of different categories and I don't know which in advance. I makes sense to create a type for each type of data the files can contain, but I'm struggling with getting this datatype out of my parser and into my model/main program.
In most other programming languages I would probably define a function/method which accepts a filename as input, and return a generic type as output. Depending on my need I would then cast or test the type of my generic returntype and get the real type of my retuned data.
However, this doesn't really seem to work in Rust. I can define a function which returns a Trait like this:
fn parse_file(file: &'str) -> impl ParsedData
where ParsedData
is a common Trait for all my DataTypes. But what do I do from here? At some point I need to seperate the different types of data hidden behind my ParsedData Trait.
Solution 1: I have found the Any trait which does make it possible to downcast a Trait to a type. But the general consensus seems to be that this is something you should avoid. I'm not sure I understand exactly why people don't like it, but if nothing else it seems to be quite a lot of work/boiler plate code to get working.
Solution 2: There is also the possibility of stuffing all the known datatypes into one big containertype, like this:
pub struct DataContainer {
pub data_type_1: Option<DataType1>,
pub data_type_2: Option<DataType2>,
pub data_type_3: Option<DataType3>,
pub data_type_4: Option<DataType4>,
}
fn parse_file(file: &'str) -> DataContainer
and the just pass that around until you need the datatypes inside of it.
Solution n: There seem to be a number of less popular solutions out there
Reading some data without knowing the type in advance must be a very common task. Isn't there a de facto way to deal with it? I read several times that the main reason downcasting suppport in Rust is poor is due to the fact that there are other, and better, way to deal with almost/every single type of problem where people run into the need of downcasting data.
So here is my question. How do you deal with this problem in an easy idiomatic way?
Problem definition:
- Lets say you want to read a number of files. Some will contain user profiles, some will contain pictures (not tied to a user) and some will contain cooking recipes.
- You do not know what a file contains before you read it, but it's easy to parse and there is no uncertainty.
- I defined a function
parse_file
above, but that was just me thinking that would be a nice interface to reading these files since they probably share a lot of code for opening the file etc.
回答1:
What you want is an enum.
If you have types DataType1
, DataType2
, DataType3
and DataType4
, you can define an enum that is guaranteed to contain only one of the data types.
enum DataContainer {
Type1(DataType1),
Type2(DataType2),
Type3(DataType3),
Type4(DataType4),
}
Then you can handle each variant with a match:
let data: DataContainer = parse(something);
match data {
Type1(x) => do_something_with_type_1(x),
Type2(x) => do_something_with_type_2(x),
Type3(x) => do_something_with_type_3(x),
Type4(x) => do_something_with_type_4(x),
}
回答2:
I think you are confusing traits with data types or generics.
A trait tells the Rust compiler about functionality a particular type has and can share with other types
So basically fn parse_file(file: &'str) -> impl ParsedData
return a type that supports the trait ParsedData
where it is defined as :
trait ParsedData{
fn some_funtion(&self) -> some_return_type;
}
Now you can do something like for all types of data_types
:
impl ParsedData for data_type_x{
fn some_funtion(&self) -> some_return_type{
// code
}
}
Now you can now directly use some_funtion
on the returned type where returned is of type data_type
( eg: let k = parse_file(&"some_str").some_function();
).
But if it return type is conditional in :
fn parse_file(file: &'str) -> impl ParsedData{
x
}
then change it into :
fn parse_file(file: &'str) -> Box<ParsedData>{
Box::new(x)
}
来源:https://stackoverflow.com/questions/60336781/idiomatic-way-of-returning-multiple-types-in-rust