7

Is there a way for me to obtain a static borrowed reference to a struct's implementation of a trait:

trait Trait {}

struct Example;
impl Trait for Example {}

This works fine:

static instance1: Example = Example;

This also works fine:

static instance2: &'static Example = &Example;

But this doesn't work:

static instance3: &'static Trait = &Example as &'static Trait;

It fails thus:

error[E0277]: the trait bound `Trait + 'static: std::marker::Sync` is not satisfied in `&'static Trait + 'static`
  --> src/main.rs:10:1
   |
10 | static instance3: &'static Trait = &Example as &'static Trait;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait + 'static` cannot be shared between threads safely
   |
   = help: within `&'static Trait + 'static`, the trait `std::marker::Sync` is not implemented for `Trait + 'static`
   = note: required because it appears within the type `&'static Trait + 'static`
   = note: shared static variables must have a type that implements `Sync`

Alternatively, is there a way to obtain a borrowed static pointer to a trait from a global borrowed static pointer to a struct:

static instance2: &'static Example = &Example;

fn f(i: &'static Trait) {
    /* ... */
}

fn main() {
    // how do I invoke f passing in instance2?
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
LorenVS
  • 12,597
  • 10
  • 47
  • 54
  • Thanks for the response, I just whipped the code together in the question, so thanks for dealing with the typos. I've updated to rust nightly, which seems to solve some issues, but do you know of anyway to cast to a static borrowed pointer to a trait in a constant expression? That seems to be the biggest problem I'm having – LorenVS Oct 29 '13 at 22:56
  • Sorry, I don't know. Using `as &'static T` would be intuitive, but the compiler rejects that. It may be that this is not possible yet. If so, you could work around it by casting the static variable whenever you use it. Or, if possible, use type params instead of trait objects. Trait objects are rarely used in Rust, most often type params will do much better. (When I started with Rust, I often used trait objects where they weren't actually necessary). E.g. `fn f(i: &T) { /* ... */ }` is a function that can be called with any object that implements MyTrait. – Zargony Oct 30 '13 at 10:34

1 Answers1

7

Yes, you can, if the trait also implements Sync:

trait Trait: Sync {}

struct Example;
impl Trait for Example {}

static INSTANCE3: &dyn Trait = &Example;

Or if you declare that your trait object also implements Sync:

trait Trait {}

struct Example;
impl Trait for Example {}

static INSTANCE3: &(dyn Trait + Sync) = &Example;

Types that implement Sync are those

[...] for which it is safe to share references between threads.

This trait is automatically implemented when the compiler determines it's appropriate.

The precise definition is: a type T is Sync if &T is Send. In other words, if there is no possibility of undefined behavior (including data races) when passing &T references between threads.

Since you are sharing a reference, any thread would be able to call methods on that reference, so you need to ensure that nothing would violate Rust's rules if that happens.

Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366