如何在 Rust 中干净地实现“瀑布”逻辑
发布时间:2022-07-21 21:35:44 273
相关标签: # scala
我有一个类型的集合,代表我的数据模式的各种旧版本和新版本:
struct Version1;
struct Version2;
struct Version3;
struct Version4;
这些类型可以在彼此之间迁移,一次迁移一个:
impl Version1 { fn migrate_to_v2(self) -> Version2 { Version2 } }
impl Version2 { fn migrate_to_v3(self) -> Version3 { Version3 } }
impl Version3 { fn migrate_to_v4(self) -> Version4 { Version4 } }
我有一个包含所有这些版本的枚举,这是我从磁盘读取的数据格式:
enum Versioned {
V1(Version1),
V2(Version2),
V3(Version3),
V4(Version4),
}
我想写一个函数来执行Versioned
反对Version4
. 有多种方法可以做到这一点,但都有明显的缺陷;我的问题是,还有其他我忽略的解决方案吗?
- 直接调用方法。问题是指数膨胀;随着我在该产品的生命周期内添加更多版本,该代码的大小将按二次方放大:
fn migrate_versioned(versioned: Versioned) -> Version4 {
match versioned {
V1(data) => data.migrate_to_v2().migrate_to_v3().migrate_to_v4(),
V2(data) => data.migrate_to_v3().migrate_to_v4(),
V3(data) => data.migrate_to_v4(),
V4(data) => data,
}
}
- 使用一系列链接
if let
s、 这需要遍历枚举类型,并且我们失去了对match
:
fn migrate_versioned(mut versioned: Versioned) -> Version4 {
use Versioned::*;
if let V1(data) = versioned {
versioned = V2(data.migrate_to_v2());
}
if let V2(data) = versioned {
versioned = V3(data.migrate_to_v3());
}
if let V3(data) = versioned {
versioned = V4(data.migrate_to_v4());
}
if let V4(data) = versioned {
return data;
}
unreachable!();
}
- 使用
loop
. 这将恢复在中丢失的穷举性检查if let
if let
:
fn migrate_versioned(mut versioned: Versioned) -> Version4 {
loop {
versioned = match versioned {
V1(data) => V2(data.migrate_to_v2()),
V2(data) => V3(data.migrate_to_v3()),
V3(data) => V4(data.migrate_to_v4()),
V4(data) => break data,
};
}
}
- 一些连锁特征。这比其他的都好,但事实并非如此非常样板上沉重:
trait ToV2: Sized {
fn migrate_to_v2(self) -> Version2;
}
impl ToV2 for Version1 { ... }
trait ToV3: Sized {
fn migrate_to_v3(self) -> Version3;
}
impl ToV3 for Version2 { ... }
impl ToV3 for T {
fn migrate_to_v3(self) -> Version3 { self.migrate_to_v2().migrate_to_v3() }{
}
trait ToV4: Sized {
fn migrate_to_v4(self) -> Version4;
}
impl ToV4 for Version3 { ... }
impl ToV4 for T {
fn migrate_to_v4(self) -> Version3 { self.migrate_to_v3().migrate_to_v4() }{
}
fn migrate_versioned(versioned: Versioned) -> Version4 {
match versioned {
V1(data) => data.migrate_to_v4(),
V2(data) => data.migrate_to_v4(),
V3(data) => data.migrate_to_v4(),
V4(data) => data,
}
}
- 各种基于宏的解决方案。通常,它们使用宏生成一个有噪声的解决方案(例如特征版本或直接调用版本)。由于使用宏重复规则(据我所知,这需要一个复杂的递归宏)创建链接调用的相关技巧,这些往往是极其嘈杂,以至于不能有意义地说这是一种复杂性节约:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c8b8bed94afe654bbee7cfabfe24c784.
我在这里遗漏了什么解决方案吗?从概念上讲,这样做似乎很简单:
// V1 starts here
let v2 = v1.migrate_to_v2();
// V2 starts here
let v3 = v2.migrate_to_v3();
// V3 starts here
let v4 = v3.migrate_to_v4();
// v4 starts here
但我一点也不清楚如何(如果有的话)表达如此简单的解决方案的控制流。
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报