在 Rust 中,结构体可以有一个方法来获取结构体的所有权并移动它,使得以后再次使用该结构体是非法的,例如
struct Foo {}
impl Foo {
fn consume(self) -> u32 {
println!("consumed!");
42
}
}
fn main() {
let x = Foo {};
let val_1 = x.consume();
let val_2 = x.consume(); // WON'T COMPILE
}
有没有办法使用 TypeScript 的类型系统来表示类似的状态变化?
TypeScript 目前不支持子结构类型,例如线性/仿射类型,需要这些类型来表示您在此处尝试使用的所有权模型类型。在 microsoft/TypeScript#16148 上有一个长期开放的功能请求,被列为“等待更多反馈”,这意味着他们需要听到更多的社区需求,然后才能认真考虑实现它。而且这似乎还不够。如果您的用例令人信服的话,添加您的👍并描述您的用例不会“伤害”您,但它可能也没有帮助。
TypeScript 并没有真正对其类型系统中的任意状态变化进行建模。它只允许“缩小”,这意味着您最多可以对“更多的功能,所以乍一看,这并不是一件容易做到的事情。您可以使用断言函数
将
x
一直缩小到x.consume
类型,如果您调用它,将会给您一个错误。但断言函数有一些警告:它们不能返回值(因此分配给
never
起不了多大作用)并且您需要显式的 类型注释。所以我能得到的最接近你想要的东西看起来像这样:
val_1
这里 class Foo {
consume(
ret: { value: number; }
): asserts this is { consume: never } {
console.log("consumed!")
ret.value = 42;
}
}
const foo: Foo = new Foo();
const ret = { value: 0 };
foo.consume(ret);
let val1 = ret.value;
// ^?
console.log(val1); // 42
foo.consume(ret);
// ~~~~~~~
// error! This expression is not callable.
实例有一个 Foo
断言方法,该方法接受 consume()
参数,该参数充当所需返回值的容器。如果您在
ret
的实例上调用
consume()
(已明确注释为
Foo
),那么它将改变
Foo
并缩小实例范围,以便
ret
属于
consume
类型并且它无法再次调用。
这实际上是否比仅仅放弃并以其他方式表示状态更好(例如,只需让
never
可多次调用,但在第一次后返回缓存的值等)取决于您的用例。我怀疑断言方法是否可行,但这确实超出了问题的范围。
Playground 代码链接