结合了数据和功能以及接口和结构的组合

I'm wondering if this is something that's done in Go or if I'm thinking about it all wrong: composing type x interface and type x struct so my interface methods have access to specific data too:

The C programmer in my wants to do this:

type PluginHandler interface {
    onLoad()
    pm *PluginManager
}
func (ph PluginHandler) onLoad() {
    pm.DoSomething()
}

There I have an interface defined with a function, but also some data I want to pass to those functions but this is a syntax error.

So is this something that's doable in Go through some other method or am I just thinking about the problem wrong?

You have defined onLoad incorrectly. You cannot define a function directly on interface type.

Once you have an interface, you need another type to implement methods specified in the interface. For example, if another type implements onLoad method, they automatically (implicitly) implement the interface PluginHandler.

The other thing you need to do is change the interface function type to accept the required data:

type PluginHandler interface {
    onLoad(*PluginManager)
}

struct SomeType {
    // ...
}

func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
    pm.DoSomething()                          // PluginHandler interface.
}

This way, you get to inject whichever PluginManager required by PluginHandler.

Also, you can use SomeType as a PluginHandler type whereever required.

func someFuntion(ph PluginHandler) {
    // ...
    ph.onLoad(pm)
    // ...
}

Can be called with an input argument of type SomeType:

s := SomeType{}
someFunction(s)

TL;DR; There is no direct translation to Go.

Long answer:

Go interfaces are only methods.

Go structs are only data (with the possibility of receiver methods).

You can reference, and even embed interfaces within structs:

type Frobnicator interface {
    Frobnicate() error
}

type Widget struct {
    Frobnicator
    WidgetName string
}

But that's not really what you're talking about.

The best answer to your dilema is, I believe: Take a step back. You're focusing on the trees, and you need to look at the forest. Go takes a different approach than C, or classical OO languages like C++ and Java.

Look at the general problem to be solved, and find solutions to that in Go. This can be a painful process (I can say from experience), but it's really the only way to learn the new way of thinking.

Just for the record, you can add extra methods to an existing type, by introducing another (indirection) type as:

type HandlerManager PluginManager

func (x *HandlerManager) onLoad() {
    ((*PluginManager)(x)).DoSomething()
}

And if you need to go with a more generic solution, a combination of Adapter & Strategy patterns could do:

type PluginHandlerAdapter struct{ _onLoad func() }

func (x *PluginHandlerAdapter) onLoad() {
    x._onLoad()
}

Used like (public/private access ignored):

type PluginManager struct {
    PluginHandlerAdapter
}

func NewPluginManager() *PluginManager {
    res := new(PluginManager)
    res._onLoad = res.DoSomething
    return res
}