如何在 Go 中正确构建带有子包的包,其中单一类型将成为大多数方法的接收者?

问题描述 投票:0回答:2

我目前正处于编写实用程序库的设计阶段,该库将使与 x-go-binding 的交互变得更容易。 (我之前使用 Python 和 xpyb 完成过此操作。)例如,它将有助于查询 EWMH 规范 中定义的信息并将键绑定到回调函数。 (还有更多。)因此,作为我对包装布局的最初想法,请考虑:

  • xutil
    • 嗬嗬
    • 按键绑定

每个都是它自己的包。 (与标准库的镜像包设置类似。)

我的情况的独特之处在于,几乎每个 x-go-binding 调用都需要 xgb 连接对象或根窗口标识符的某种组合。因此,对我来说,将这些信息存储在如下结构中是有意义的:

type XUtilConnection struct {
    conn xgb.Conn
    root xgb.Id
    // a few other things, like a mapping of events to callbacks
}

这样我就有一个可以像这样使用的工厂:

xconn = xutil.NewXUtilConnection(blah blah)

它可以这样使用:

xconn.get_active_window()
xconn.bind_key("Shift-a", my_callback_fun)

还可能有这样的功能:

keybind.get_keycode("a")
ewmh.get_atom("_NET_ACTIVE_WINDOW")

我的问题当然是,据我所知,接收器只能是在同一个包中声明的类型。如果我分离我的包,我就无法在任何子包中使用我的 XUtilConnection 类型作为接收器。

我怀疑我的答案是将这个大包分成不同的逻辑文件,但我担心这可能会导致命名空间混乱。 (例如,实现 EWMH 规范可能需要 100 多个函数。)

我还知道我可以在 XUtilConnection 对象的每个子包中定义一个新的容器类型。 (我听说这应该是一个包含单个成员 XUtilConnection 的结构,以避免强制转换。)但这对我来说似乎是一个非常混乱的情况,并且会阻止我想要的那种语义。 (即,使用 XUtilConnection 结构调用多个不同模块中的方法。)

go package
2个回答
2
投票

我建议使用嵌入

包装内

xutil

type XUtilConnection struct {
    *ewmh.EWMH        // Embed all methods of *ewmh.EWMH
    *keybind.KeyBind  // Embed all methods of *keybind.KeyBind
}

包装内

xutil/ewmh

type EWMH struct {
    Conn xgb.Conn
    Root xgb.Id
    // and any additional fields that are needed
}

// Some EWMH methods:
func (e *EWMH) GetAtom(name string) { ... }
func (e *EWMH) ...

包装内

xutil/keybind

type KeyBind struct {
    Conn xgb.Conn
    Root xgb.Id
    // and any additional fields that are needed
}

// Some keybind methods:
func (k *KeyBind) GetKeyCode(s string) { ... }
func (k *KeyBind) ...

这将使您能够直接对

EWMH
类型的值调用
KeyBind
*XUtilConnection
的方法:

var c *XUtilConnection = ...
c.GetAtom("_NET_ACTIVE_WINDOW")  // Call (*emwh.EWMH).GetAtom(string)
c.GetKeyCode("a")                // Call (*keybind.KeyBind).GetKeyCode(string)

0
投票

我不确定我是否正确理解了这个问题(我对看到包名称感到困惑,它们似乎被讨论为方法接收者?),但我想传递一个接口而不是 [*] 结构将能够满足它来自任何包内。人们也可以总是做类似的事情(完全未经测试的代码):

package foo

type Foo interface { Bar(); Baz() }

----
package qux

import "foo"

type qux struct { foo.Foo; myStuff t }

func Foo(f foo.Foo) foo.Foo {
    return qux{f, &t{}}
}

func (q qux) Bar() {
    // smthg
}

例如包

f.Bar
中的“覆盖”
qux
和“继承”
f.Baz()
不变。

© www.soinside.com 2019 - 2024. All rights reserved.