golang public 方法到私有结构 - 这有任何用例吗

golang public method to private struct - is this have any use case

我是新来的。我注意到在一些库中有 public 私有结构的方法。例如参见 [​​=11=]

这有实际用例吗?如果我也无法访问它们所属的结构,我无法想象我将如何使用 public 方法。

如以下问题 - 有什么方法可以克服结构的私有声明吗?例如,我想在我的包中使用指向文件中的结构堆栈。

这是取消导出它的提交:https://github.com/btcsuite/btcd/commit/7411e65b1e8d4e4c6da198590ad627bfe253173c。来自提交消息:

This commit unexports the Stack type since it is only intended to be used internally during script execution. Further, the engine exposes the {G,S}etStack and {G,S}etAltStack functions which return the items as a slice of byte slices ([][]byte) for caller access while stepping.

我相信你是正确的,你(在包之外)不能使用这个结构。它纯粹在包实现中使用。

因此,主要用例是您可以 return 从包函数中获取未导出的类型。然后可以在此类型上使用任何导出的方法,即使其他包实际上不能首先创建该类型(除了从您的包中将其作为 return 值接收)。

package foobar

type foo struct {}
func (f foo) Bar() {}
func Newfoo() foo {
    return foo{}
}
----
package main
func main() {
    f := foobar.Newfoo()
    f.Bar()

    foobar.NewFoo().Bar()
}

另一个主要用例是包级接口。我倾向于使用一个相当标准的模式,其中一个包定义了一个导出接口,如下所示:

type Doer interface {
    Do()
}

然后定义一些满足该接口的私有类型:

type stringDoer struct {}

func (s *stringDoer) Do() {}

func NewStringDoer() Doer {
    return &stringDoer{}
}

这样外部包就可以使用我的类型作为接口,而不必弄乱具体类型,并且由于我的包公开的数据类型完全是接口,它会对我的包进行模拟或存根调用(例如,对于测试)非常简单。

要使此类系统正常工作,必须导出结构(在本例中为 stringDoer)上的方法,即使结构本身不是。

通常我们用它来为我们的代码提供额外的保护。所以,基本上,你的空类型应该是有意义的,但有时为了防止使用文字语法制作结构,或者当我们为字段初始化做一些工作时,我们按照约定对结构使用新函数。例如:

type A struct {
    F1 string
    F2 int
    F3 bool
    f4 string
}

func NewA(f1 string, f2 int) *A {
    a := A{
        F1: f1,
        F2: f2, 
        F3: // some work for initialization
        f4: // some work for initialization
    }

    return &a
}

如果类型是私有的并且有 public 方法,我们还有其他函数将此类型作为 return 值。所以,在这里我们可以得到它,通常这个函数命名为New有时我们这样做的主要原因是没有人不能使用其他方式创建或获取此类型,但可以使用它的 public 方法。此外,这种类型的字段通常也是私有的。这是我 uci 库实现的一小部分代码。

package uci

type target struct {
    config  string
    options []string
}

func Target(config string, options ...string) (target, error) {
    if config == "" {
        return target{}, emptyOptionErr
    }

    for _, opt := range options {
        if opt == "" {
            return target{}, emptyOptionErr
        }
    }

    aim := target{
        config:  config,
        options: options,
    }

    return aim, nil
}

// code with target public methods, etc...