我正在 Rust 中制作一个 Tic-Tac-Toe 游戏作为初学者项目,当我遇到这个问题时,我正在计算游戏的状态(获胜、平局等)。我首先写了下面的代码:
fn status(&self) -> Status {
if Board::has_won(self.x_board) {
Status::Won(true)
} else if Board::has_won(self.o_board) {
Status::Won(false)
} else if self.is_full() {
Status::Draw
} else {
Status::None
}
}
Run Code Online (Sandbox Code Playgroud)
然后我修改它以返回引用:
fn status(&self) -> &Status {
if Board::has_won(self.x_board) {
&Status::Won(true)
} else if Board::has_won(self.o_board) {
&Status::Won(false)
} else if self.is_full() {
&Status::Draw
} else {
&Status::None
}
}
Run Code Online (Sandbox Code Playgroud)
我这样做是为了将 self 的生命周期和返回值链接在一起,因此如果板的状态发生更改,则无法再使用对状态的引用。
然后我尝试了这段代码:
fn status(&self) -> &Status {
let status;
if Board::has_won(self.x_board) {
status = Status::Won(true)
} else if Board::has_won(self.o_board) {
status = Status::Won(false)
} else if self.is_full() {
status = Status::Draw
} else {
status = Status::None
}
&status
}
Run Code Online (Sandbox Code Playgroud)
它导致编译器错误,指出它无法返回对拥有数据的引用。为什么第一个片段没有这个问题?
我的猜测是,第一个片段受到生命周期扩展的影响,而第二个片段是对显式局部变量的引用,因此已经具有显式生命周期。延长生命周期的规则很复杂,因此我将让其他人讨论其细节。相反,我想提出一个稍微不同的设计。
你所做的事情令人钦佩。事实上,这太棒了。我从未想过将这样的状态变量与带有引用的数据结构联系起来。话虽这么说,你在这里对 Rust 撒了一点谎,我们可以更直接地得到你想要的行为。
基本上,你有一个Status. 它是一个值,它不是借来的,假装它是借来的只是有点尴尬。这并没有错,只是尴尬。但您希望它在语义上表现得像借来的,即使事实并非如此。我们可以使用 aPhantomData来做到这一点。
考虑一下这一点。不要Status管你的枚举。制作它Copy和Clone,因为它又好又简单,并且永远不要引用它。它仍然可以作为独立的数据结构合理地使用,只要您永远不会假设它与任何特定的板相关联。
现在,当您想将其绑定到特定的板时,请使用一个新的结构,我将其称为BoardStatus.
struct BoardStatus<'a> {
status: Status,
_phantom: PhantomData<&'a Status>,
}
Run Code Online (Sandbox Code Playgroud)
ABoardStatus确实只是一个Status。它唯一的非零大小字段是 a Status,因此两者的表示形式应该相同。但它也有一个PhantomData. PhantomData<T>是一个零大小的类型(意味着它在运行时不占用空间),假装包含用于T生命周期的目的。假装借用持续时间 的BoardStatusa Status(拥有的状态值,无借用)也是如此。那么你的方法就可以有这个返回类型。'astatus
fn<'a> status(&'a self) -> BoardStatus<'a>
Run Code Online (Sandbox Code Playgroud)
或者,终身省略
fn status(&self) -> BoardStatus<'_>
Run Code Online (Sandbox Code Playgroud)
这样,Status枚举之间就有了区别,它是可独立测试的并且没有额外的包袱;以及BoardStatus结构,它仍然只是一种状态,但明确与董事会相关联。
最好的部分是:这一切都是零开销。运行时没有实际的指针,因此BoardStatus与运行时的效率完全相同Status,没有间接寻址。真正的零成本抽象。
| 归档时间: |
|
| 查看次数: |
93 次 |
| 最近记录: |