6

I have a project which relies on a struct imported from another package, which I will call TheirEntity.

In the example below, I (ahem) embed TheirEntity in MyEntity, which is an extension of TheirEntity, with added functionality.

However, I don't want to export TheirEntity in the MyEntity structure, as I would rather the consumer not access TheirEntity directly.

I know that Go embedding is not the same as inheritance in classical OOP, so maybe this is not the correct approach, but is it possible to specify embedded structs as "private", even if they are imported from another package? How might one achieve the same thing in a more idiomatic fashion?

// TheirEntity contains functionality I would like to use...

type TheirEntity struct {
    name string
}

func (t TheirEntity) PrintName() {
    fmt.Println(t.name)
}

func NewTheirEntity(name string) *TheirEntity {
    return &TheirEntity{name: name}
}

// ... by embedding in MyEntity

type MyEntity struct {
    *TheirEntity // However, I don't want to expose 
                 // TheirEntity directly. How to embed this
                 // without exporting and not changing this
                 // to a named field?

    color        string
}

func (m MyEntity) PrintFavoriteColor() {
    fmt.Println(m.color)
}

func NewMyEntity(name string, color string) *MyEntity {
    return &MyEntity{
        TheirEntity: NewTheirEntity(name),
        color:       color,
    }
}
dtg
  • 1,803
  • 4
  • 30
  • 44

3 Answers3

13

Since the question was asked, Go saw the addition of type aliases to the language with the 1.9 release in 2017. It turns out that, through an unconventional use of type aliases, you can have your cake and eat it too!

First, declare an unexported alias for the third-party type you wish to embed in your struct:

type theirEntity = TheirEntity

Then, simply embed that alias instead of the original type:

type MyEntity struct {
    *theirEntity
    color string
}

(Playground)

jub0bs
  • 60,866
  • 25
  • 183
  • 186
4

[I]s it possible to specify embedded structs as "private", even if they are imported from another package?

No.

How might one achieve the same thing in a more idiomatic fashion?

By not-embedding but making it a unexported named field.

Volker
  • 40,468
  • 7
  • 81
  • 87
  • 1
    I suspected as much. The downside to the named field is that, in this scenario, I have to implement several functions in `MyEntity` as part of a contract to several interfaces that `TheirEntity` implements. Embedding allows me to satisfy that contract without having to reimplement. – dtg Nov 25 '15 at 19:20
4

Like this:

type MyEntity struct {
    *privateTheirEntity
}

type privateTheirEntity struct {
    *TheirEntity
}
Greg Dennis
  • 65
  • 1
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 10 '21 at 23:24