2016-01-07 5 views
2

Я пытаюсь написать простую игру с 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); 
    } 
} 

ответ

2

Я не знаком с ржавчиной-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 может» t удаляет кадр стека функции-конструктора. Вам нужно будет передать готовый 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 } } 
    } 
} 

toy example on the playground

+0

Ну, я, вероятно, в конечном итоге писать синглтона FontManager или что-то подобное, так что удаление Шрифт из конструктора ISN» Это действительно проблема. Но мне все еще немного интересно, как я могу создавать компоненты, если они начинают требовать создания всего за пределами структуры. –

+2

Если ваш компонент владеет своими подкомпонентами (вместо ссылки на них), вы можете собрать их все в одном месте. В этом случае Font создается из файла (относительно дорогостоящая операция), и обычно будут различные фрагменты текста, созданные с помощью этого одного шрифта, поэтому имеет смысл загрузить все нужные шрифты в начале и просто поделиться ссылками на них , –