Sharing reference of `this` in constructor


#1

Coming from JavaScript, I’m learning Rust, and I keep running into the same issue.

Let’s say that I’m building a native window wrapper. Something like this:

struct MyWindowWrapper {
  native_window: …; // Native window type
}

impl MyWindowWrapper {
  fn new() {
    let native_window = …; // Some platform specific code.
    MyWindowWrapper {
      native_window: native_window
    }
  }
  fn update_title(&self, title: String) {
    self.native_window.set_title(title);
  }
}

Now, this works. Now I also want MyWindowWrapper to handle events from the native window (let’s say, on_window_clicked). So I add a method to MyWindowWrapper and want native_window to call it. So native_window need a reference to the new instance of MyWindowWrapper:

impl MyWindowWrapper {
  fn new() {
    let native_window = …; // Some platform specific code.
    let wrapper = MyWindowWrapper {
      native_window: native_window
    };

    native_window.set_handler(&wrapper);

    wrapper
  }
  fn update_title(&self, title: String) {
    self.native_window.set_title(title);
  }
  fn on_window_clicked(&self) {
     // will be called by native_window.
  }
}

But in the implementation of set_handler, I can’t keep the reference to the wrapper. Rust bails with expected lifetime parameter when I try to use a struct that holds a reference to MyWindowWrapper.

Maybe I need a lifetime indeed. I was also wondering if I should be using Rc<MyWindowWrapper>.

Edit: just tried with a lifetime, and it works. But I’m wondering if it’s the right way to do it.

But I want to do understand what is the “Rust” way to do such a thing.

Any feedback would be appreciated. Thank you.


#2

If the “native window” stuff is a C library, there’s not much you can do about safely life-timing it: You have to cast the reference into a raw pointer and do your best to avoid destroying the underlying data as long as the C library may use that pointer. If you use a Rust wrapper around the native window, that wrapper will do the aforementioned unsafe thing for you, but it will still be done. How you use lifetimes with that wrapper then depends on the function signatures of the wrapper.
Also please read this, if you haven’t already: https://doc.rust-lang.org/book/lifetimes.html


#3

Seeing full definition of MyWIndowWrapper and native_window would help here! Seems like you want two structures which reference each other. This is possible in Rust with unsafe or horrible Rc/Weak code, but it’s better and simpler just to avoid cycles in the first place.


#4

Exactly. That’s my problem. I ended up working around the cycle. And it appears to work fine.


#5

What does native_window.set_handler(&wrapper); actually do? It can’t just store reference to wrapper inside native_window, because the lifetimes won’t work out, wrapper is a local variable…