【问题标题】:Rust (+SFML) - How to avoid extra object construction when limited by lifetime parameters?Rust (+SFML) - 如何在受生命周期参数限制时避免额外的对象构造?
【发布时间】:2014-06-26 03:57:52
【问题描述】:

我目前正在使用rust-sfml (rsfml::graphics) 在屏幕上绘制像素。 (我只是从 Rust 和项目开始。)我将数据存储在 Image,然后复制到 Texture

这个Texture用来创建一个Sprite<'s>;这就是我的问题。我需要能够改变Texture,但Sprite<'s> 的类型似乎保证我不能做我想做的事。因为每次重绘窗口时我都需要能够调用window.draw(&sprite),所以我每次都创建一个新的Sprite

更好的选择是将Sprite<'s>Texture 一起保留在我的struct Render 中。由于'Sprite'有一个生命周期参数,它变成struct Render<'s>

struct Render<'s> {
    texture: Texture,
    sprite: Sprite<'s>,
}

我在Render上有一个方法:

fn blit(&'s mut self) -> ()

它改变了Render(通过编辑Texture)。现在,只要我尝试多次调用blit,就会遇到这个问题:

render.blit();
render.blit();  // error: cannot borrow `render` as mutable more than once at a time

我认为,这是因为生命周期参数强制 Render 的生命周期作为第一借用-blit-调用等于 Render 实例的生命周期(整个 main 函数)。

我怎样才能保留我原来的Sprite 并继续能够改变容器?有可能吗?

这是一个看起来很愚蠢但相当简单的例子:

extern crate rsfml;

use rsfml::graphics::Sprite;

fn main() -> () {
    let mut render = Render::new();
    render.blit();
    render.blit();  // error: cannot borrow `render` as mutable more than once at a time
}

struct Render<'s> {
    sprite: Option<Sprite<'s>>,
}

impl<'s> Render<'s> {
    fn new() -> Render { Render { sprite: None } }
    fn blit(&'s mut self) -> () { }
}

(如果问题不清楚,请见谅。当我对概念不是很熟悉时,很难表达。)

【问题讨论】:

  • 这没有意义——如果你的代码真的只是render.blit(); render.blit();,那么要么两者都不起作用,要么两者都起作用。你能发布更完整的代码吗?
  • 谢谢,克里斯。我做了一个半最小的例子,并附在最后。
  • 仅供参考,-&gt; () 部分是多余的,'s 在您的blit 调用中也是如此。
  • Eww...在您的blit 定义中使用's 是导致它的原因。它使借款持续时间更长。当然,现在我看到了……
  • 好吧,当我有实际代码使用 sprite 时,就需要 blit 定义中的 's(我认为...)。

标签: sfml rust lifetime lifetime-scoping


【解决方案1】:

当您致电blit 时,有两个生命周期正在考虑中; self,你看,在某些生命周期 ρ₀ 和 ρ₁ 中是 &amp;'ρ₀ Render&lt;'ρ₁&gt; 类型。在您的 impl&lt;'s&gt; Render&lt;'s&gt; 声明中,您已声明 ρ₁ 是 's,并且在您的 &amp;'s mut self 中您已声明 ρ₀ 是 's:因此,self 的借用的生命周期是 @987654329 @,这意味着你只能有一个借用,因为它会一直存在直到类型被销毁——它被声明为“至少与被引用的类型一样长”。

你想改变它来为blit函数引入一个生命周期参数,该参数允许小于's;您希望 ρ₀ 最小,只与返回值相关(我假设您实际上使用的是's——如果不是,您应该忽略它并允许编译器显式推断我们将要编写的内容)。这样,借用只会在函数的返回值仍在作用域内时才有效(在您的简单示例中,它没有被使用,因此您可以立即获取另一个引用)。

那么,这就是需要对功能进行的更改:

fn blit<'a>(&'a mut self) { }

如果您将其更改为具有返回值并使用它,则需要在再次调用 blit 之前确保它超出范围。这可能意味着将其直接传递给函数,也可能意味着引入新的作用域,如下所示:

{
    let foo = render.blit();
    // … do things with foo … it then gets freed at the end of the block.
}
render.blit();

【讨论】:

  • 谢谢!我现在遇到了另一个问题,我想这一直是问题的根源:如果blit 调用self.sprite.set_texture(&amp;self.texture, true),我会得到error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements。我应该编辑问题吗?做一个新的?
  • 我想你会发现像这样将精灵和纹理捆绑在一起是无法表达的。你可能想在 Rust IRC 频道(或者更好,#rust-gamedev)中讨论它
  • 碰巧我明天要去 Mozilla 的 Rust 游戏技术聚会;所以也许接触它会让一切变得更清晰。
  • @KaiNinomiya:那里会有人谈论你的问题!
猜你喜欢
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 2023-02-15
相关资源
最近更新 更多