Проблемы со временем жизни, когда один экземпляр структуры нуждается в ссылке на другой

Я пытаюсь написать простую игру с SFML и Rust, но средство проверки заимствований оказывается моим главным врагом в этом путешествии.

Существует множество случаев, когда SFML нужна ссылка на другой объект. В приведенном ниже коде мне нужна ссылка на шрифт, иначе текст ничего не показывает пользователю.

Проблема в том, что я перепробовал кучу вещей, а сама ссылка никогда не живет достаточно долго. Очевидно, это работает, если я создаю объект Text в методе draw, но я бы хотел избежать создания вещей внутри основного цикла приложения.

Это тот случай, когда мне стоит взглянуть на небезопасные операции? Существует ли комбинация Rc, RefCell, Box и т. Д., Которая отвечает моим потребностям?

Пожалуйста, попытайтесь объяснить мне, что я должен делать и что не так в моем нынешнем мышлении, если это возможно.

extern crate sfml;

use sfml::system::{ Clock, Vector2f };
use sfml::graphics::{ Color, Font, RenderTarget, RenderWindow, Text, Transformable };

pub struct FpsMeter<'a> {
    position: Vector2f,
    clock:    Clock,
    value:    f32,

    text:     Text<'a>
}

impl<'a> FpsMeter<'a> {
    pub fn new() -> Self {
        let font = match Font::new_from_file("assets/sansation.ttf") {
            Some(fnt) => fnt,
            None      => panic!("Cannot open resource: sansation.ttf"),
        };

        let mut text = Text::new_init(
            &format!("FPS: {}", 0),
            &font,
            20  
        ).expect("Could not create text");

        FpsMeter {
            position: Vector2f::new(0., 0.),
            clock:    Clock::new(),
            value:    0.,

            text: text,
        }
    }

    pub fn set_position2f(&mut self, x: f32, y: f32) {
        self.position.x = x;
        self.position.y = y;
    }

    pub fn restart(&mut self) {
        self.value = 1. / self.clock.restart().as_seconds();
    }

    pub fn draw(&mut self, window: &mut RenderWindow) {
        self.text.set_position(&self.position);
        self.text.set_color(&Color::white());

        window.draw(&self.text);
    }
}

1 ответ

Решение

Я не знаком с rust-sfml, поэтому, возможно, я неправильно понял вашу проблему, но она должна выглядеть следующим образом. У тебя есть Font а также Text (что вы не контролируете, они созданы для вас библиотекой) где Text содержит ссылку на Font, Упрощенная:

struct Font;
struct Text<'a> { font: &'a Font }

Тогда у вас есть FpsMeter (что вы делаете контроль), который имеет Text поле. Опять упрощенно:

struct FpsMeter<'a> {
    text: Text<'a>
}

Теперь, если это так, я не думаю, что вы можете создать Text (или по крайней мере Font) в том же методе, где вы создаете FpsMeter, как ссылка на Font не может выйти из стекового фрейма функции конструктора. Вам нужно будет пройти предварительно построенный Text вашему конструктору. Например:

impl<'a> FpsMeter<'a> {
    fn new(txt: Text<'a>) -> FpsMeter<'a> {
        FpsMeter { text: txt }
    } 
}

или возможно:

impl<'a> FpsMeter<'a> {
    fn new(fnt: &'a Font) -> FpsMeter<'a> {
        FpsMeter { text: Text { font: fnt } }
    } 
}

пример игрушки на детской площадке

Другие вопросы по тегам