组合将数据和函数与接口和结构体结合在一起。

huangapple go评论81阅读模式
英文:

Composition combining data and functions with interfaces and structs

问题

我想知道这是否是Go语言中的一种做法,或者我是否完全错误地思考了这个问题:通过组合type x interfacetype x struct,使得我的接口方法也可以访问特定的数据:

我想要像C语言程序员那样做:

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

在这里,我定义了一个带有函数的接口,但是还有一些数据我想要传递给这些函数,但是这是一个语法错误。

所以,是否有其他方法可以在Go语言中实现这个功能,还是我对问题的思考方式有误?

英文:

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?

答案1

得分: 2

你已经错误地定义了onLoad。你不能直接在接口类型上定义一个函数。

一旦你有了一个接口,你需要另一个类型来实现接口中指定的方法。例如,如果另一个类型实现了onLoad方法,它们就会自动(隐式地)实现PluginHandler接口。

另一件需要做的事情是将接口函数类型更改为接受所需数据:

type PluginHandler interface {
    onLoad(*PluginManager)
}

type SomeType struct {
    // ...
}

func (s SomeType) onLoad(pm *PluginManager) { // SomeType现在实现了
    pm.DoSomething()                          // PluginHandler接口。
}

这样,你可以注入任何PluginHandler所需的PluginManager

此外,你可以在需要的地方将SomeType用作PluginHandler类型。

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

可以使用SomeType作为输入参数的类型调用:

s := SomeType{}
someFunction(s)
英文:

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)

答案2

得分: 1

TL;DR; Go没有直接的翻译。

长答案:

Go的接口只包含方法。

Go的结构体只包含数据(可以有接收者方法的可能性)。

你可以在结构体中引用甚至嵌入接口:

type Frobnicator interface {
    Frobnicate() error
}

type Widget struct {
    Frobnicator
    WidgetName string
}

但这并不是你所说的。

对于你的困境,我认为最好的答案是:退一步。你现在过于关注细节,需要放眼整体。Go采用了与C、C++和Java等传统面向对象语言不同的方法。

看看要解决的一般问题,并在Go中找到解决方案。这可能是一个痛苦的过程(我可以从经验中说),但这确实是学习新思维方式的唯一途径。

英文:

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.

答案3

得分: 0

只是为了记录,你可以通过引入另一个(间接)类型来向现有类型添加额外的方法,例如:

type HandlerManager PluginManager

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

如果你需要更通用的解决方案,可以结合适配器模式和策略模式,例如:

type PluginHandlerAdapter struct{ _onLoad func() }

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

使用方式(忽略公共/私有访问):

type PluginManager struct {
    PluginHandlerAdapter
}

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

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
}

huangapple
  • 本文由 发表于 2017年4月13日 15:14:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/43385805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定