Static access to "enum" member

n00b warning...
I wanted to have a new() method as alternative to using a macro. Dumb idea?

trait Trait {
    fn do_stuff(&self);
}

struct Foo {
    vector: Vec<String>,
}

impl Trait for Foo {
    fn do_stuff(&self) {
        println!("Foo");
    }
}
struct Bar {}

impl Bar {}

impl Trait for Bar {
    fn do_stuff(&self) {
        println!("Boo");
    }
}

enum FooOrBar {
    Foo(Foo),
    Bar(Bar),
    Special(i64),
}

impl FooOrBar {
    fn new_bar() -> FooOrBar {
        FooOrBar::Foo(Foo {
            vector: Vec::<String>::new(),
        })
    }

    pub fn do_stuff(&self) {
        self.as_trait().do_stuff();
    }

    fn as_trait(&self) -> &dyn Trait {
        match self {
            FooOrBar::Foo(f) => f,
            FooOrBar::Bar(b) => b,
            _ => panic!("Not permitted")
        }
    }
}

fn main() {
    // Yeah, macros the "workaround"
    let a = FooOrBar::Foo(Foo {vector: Vec::<String>::new()});
    a.do_stuff();
    let f = FooOrBar::new_bar();
    let s = FooOrBar::Special(6);
    // *** DOES NOT COMPILE ***
    let p = FooOrBar::Foo::new();
}

I probably don't understand what you're wanting to do, but does this help?

impl Foo {
    fn new() -> Self {
        Self {
           vector: Vec::new(),
        }
    }
}

fn main() {
    // ...
    let p = FooOrBar::Foo(Foo::new());
}

Thanx! The idea was simply hiding (for users) a potentially a bit more elaborate constructor behind a new() method as shown by the sample code. That Foo uses a Vec internally, should stay internal.

I only need to know if static access to enum members is possible or not.

Not for constructing them. You can deconstruct them using patterns, however.

I see :sleepy_face: I had hoped on something like:

impl FooOrBar::Foo {
  fn new() -> FooOrBar {
  }
}

in rust, variants of an enum are NOT themselvs types [1]. you cannot define associated functions for them.

I'm not sure what you are trying to achieve, or what you mean by "workaround", but it is common to define dedicated constructors to create specific variant of an enum, just like what you did with FooOrBar::new_bar().

can you explain what's your goal here?


  1. EDIT: techinically they are, but you cannot use them like other types, they are special kind of types ↩︎

Here's some info from the reference on this:

Each variant defines its type in the type namespace, though that type cannot be used as a type specifier. Tuple-like and unit-like variants also define a constructor in the value namespace.

A struct-like variant can be instantiated with a struct expression.

A tuple-like variant can be instantiated with a call expression or a struct expression.

A unit-like variant can be instantiated with a path expression or a struct expression. For example:

what do you mean by "access", precisely?

if you have access to the enum, you have access to all its variant. private or public don't apply to variants, but only the enum itself, if that's what you mean.

I only wanted to create a public API pattern that (in my eyes...) looks prettier (and more logical) than FooOrBar::new_bar(). imagine there are many enum members. Some of the members (like Foo) have no arguments while others like Special have explicit arguments, all preferably following the same pattern.

Well, I you had the right to dream (...) it would be cool if you could intercept the enum implicit constructor so you could end-up with FooOrBar::Foo() :fire:

Yeah, my terminology may not be correct but I thought the example would cover that :wink:

I guess my question has been answered.

I see. you'll get a feel what idiomatic rust APIs look like as you write more and more code.

side note:

the term "constructor" in rust is just a convention, it's not a special language concept. any function that returns a value of type T can be considered a constructor for T. specifically, it doesn't have to be an associated function of T either.

/// some type
enum Foo {
  //...
}

/// this is a "constructor" for type `Foo`
fn foo() -> Foo {
    todo!()
}

impl Foo {
    /// this is another more conventional constructor, with the name being `new`
    fn new() -> Self {
        todo!()
    }
}

/// but this is also a constructor, note it's async and fallible
/// as you see, the function name doesn't really matter, and the return type
/// doesn't need to be just `Foo` either, it can be "embelished"
fn make_fancy_foo() -> impl Future<Output = Result<Self, MyError>> {
    async { todo!() }
}