在 Rust 中返回多种类型的惯用方式 [英] Idiomatic way of returning multiple types in Rust

查看:210
本文介绍了在 Rust 中返回多种类型的惯用方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个解析多个文件的程序.这些文件可以分为许多不同的类别,我事先不知道是哪一个.我为文件可以包含的每种类型的数据创建一个类型是有意义的,但我正在努力将这种数据类型从我的解析器中获取到我的模型/主程序中.

在大多数其他编程语言中,我可能会定义一个函数/方法,它接受一个文件名作为输入,并返回一个通用类型作为输出.然后,根据我的需要,我将转换或测试我的通用返回类型的类型,并获取我重新调整的数据的真实类型.

然而,这在 Rust 中似乎并不真正有效.我可以定义一个函数,它返回一个像这样的特征:

fn parse_file(file: &'str) ->impl ParsedData

其中 ParsedData 是我所有数据类型的共同特征.但是我该怎么做呢?在某些时候,我需要分离隐藏在 ParsedData Trait 后面的不同类型的数据.

解决方案 1: 我发现 Any trait 确实可以将 Trait 向下转换为类型.但普遍的共识似乎是你应该避免这种情况.我不确定我是否完全理解为什么人们不喜欢它,但如果不出意外,它似乎需要大量的工作/样板代码才能开始工作.

解决方案 2: 也有可能将所有已知数据类型填充到一个大容器类型中,如下所示:

pub struct DataContainer {pub data_type_1:选项,pub data_type_2:选项,pub data_type_3:选项,pub data_type_4:选项,}fn parse_file(file: &'str) ->数据容器

并且只是传递它,直到您需要其中的数据类型.

解决方案 n:似乎有许多不太受欢迎的解决方案

<小时>

在事先不知道类型的情况下读取一些数据一定是一项非常常见的任务.难道就没有实际的处理方法吗?我读了好几次,Rust 中向下转换支持不佳的主要原因是因为有其他更好的方法来处理几乎/每一种类型的人们遇到向下转换数据需求的问题.

所以这是我的问题.您如何以一种简单的惯用方式处理这个问题?

问题定义:

  • 假设您要读取多个文件.有些将包含用户个人资料,有些将包含图片(与用户无关),有些将包含烹饪食谱.
  • 在阅读文件之前,您不知道文件包含什么内容,但它很容易解析并且没有不确定性.
  • 我在上面定义了一个函数 parse_file,但这只是我认为这将是读取这些文件的一个很好的界面,因为它们可能共享许多用于打开文件等的代码.

解决方案

你想要的是一个 枚举.

如果你有 DataType1DataType2DataType3DataType4 类型,你可以定义一个枚举保证只包含其中一种数据类型.

enum DataContainer {类型 1(数据类型 1),类型2(数据类型2),类型 3(数据类型 3),Type4(DataType4),}

然后您可以使用 match<处理每个变体/code>:

让数据:DataContainer = parse(something);匹配数据{类型 1(x) =>do_something_with_type_1(x),类型 2(x) =>do_something_with_type_2(x),类型 3(x) =>do_something_with_type_3(x),类型 4(x) =>do_something_with_type_4(x),}

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.

解决方案

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),
}

这篇关于在 Rust 中返回多种类型的惯用方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆