0

Given something like this:

type Foo struct {
  x int
}

type FooFoo struct {
  foo *Foo
}

type Bar struct {
  x int
}

Where Foo is hidden (in my case due to vendoring), how can I create a FooFoo struct with a valid foo entry?

If Foo were available, I could do

foofoo := &FooFoo{ foo: &Foo{5} }

or even

foofoo := &FooFoo{ foo: (*Foo)&Bar{ 5 } }

But I can't find a way to do it without mentioning Foo.

I think I would need something like:

foofoo := &FooFoo{ foo: (*typeof(FooFoo.foo)) &Bar{ 5 } }
Fozi
  • 4,973
  • 1
  • 32
  • 56
  • You won't be able to typecast Bar in this way. Maybe you could look into using interfaces of some sort? – Anish Goyal Mar 20 '17 at 21:38
  • 1
    Vendoring per se does _not_ "hide" types. Could you come up with a real example? Yours does not really show the actual problem. – Volker Mar 21 '17 at 06:53
  • An example of this issue is described [here](https://github.com/golang/go/issues/12432): Essentially the type `T` from the a.go vendored in b is inaccessible outside of b. – Fozi Mar 22 '17 at 04:39

2 Answers2

1

You shouldn't set the private method from another library as per this answer. However, the library should have an appropriate constructor. The library should have a method that looks like

func FooFooGenerator(appropriateInfo int) FooFoo {
 ... Library does the work 
}
Community
  • 1
  • 1
Benjamin Kadish
  • 1,472
  • 11
  • 20
  • The problem is not that it's a private field, it's that Foo is not available due to vendoring. If Foo was not vendored the problem would not exist. Unfortunately it does not have the constructor. – Fozi Mar 21 '17 at 03:34
  • Im not sure what you mean by vendored. As far as I can tell you mean its a private variable (has a lower case letter in the struct) If it is a private field in a library you didn't write there should be a method or you aren't using the library as intended (or it was written poorly) If it is a library you wrote, make it public? – Benjamin Kadish Mar 21 '17 at 12:51
0

You just need to export a "constructor" function for FooFoo and keep your foo unexported.

func NewFooFoo() *FooFoo {
    f := &foo{ /* initialize foo */ }
    return &FooFoo{foo:f}
}

Then clients of you package will have access to NewFooFoo, and FooFoo, but not foo.

And as for casting Foo to Bar, not sure why you would want that, but you can do it, if you are on Go1.8+, this way (*Foo)(&Bar{ 5 }) playground.

mkopriva
  • 35,176
  • 4
  • 57
  • 71