gsf
gsf

Reputation: 7242

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

I am new to go. I noticed in some libraries there are public methods to a private struct. See for example https://github.com/btcsuite/btcd/blob/master/txscript/stack.go

Does this have a real use case? I cannot picture how I will be able to use public methods, if I cannot access the structure they belong too.

As the following question - is there any way to overcome the private declaration of a struct? For example, I would like to use the structure stack from the pointed file in my package.

Upvotes: 13

Views: 15572

Answers (3)

Kenplix
Kenplix

Reputation: 11

Usually we use it for additional protection for our code. So, basically, your empty types should be meaningful, but sometimes to prevent making structs using literal syntax or when we make some work for fields initialization we use New function by convention for the structs. For example:

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
}

In case when type is private and have public methods we also have other function which have this type as return value. So, here we can get it, usually this function named like New. The main reason why sometimes we do it is that nobody can't create or get this type using other way, but can use it's public methods. Also fields in this types are usually private too. Here a little part of my code for uci library implementation.

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...

Upvotes: 1

Kaedys
Kaedys

Reputation: 10138

So, the major use case for this is that you can return an unexported type from a package function. Any exported methods can then be used on this type, even though other packages can't actually create the type in the first place (except for receiving it as a return value from your package).

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()
}

The other major use case is in package-level interfaces. I tend to use a fairly standard pattern wherein a package defines an exported interface, like this:

type Doer interface {
    Do()
}

And then defines some private type(s) that fulfills that interface:

type stringDoer struct {}

func (s *stringDoer) Do() {}

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

That way external packages can use my types as interfaces without having to mess around with concrete types, and since the exposed data types of my package are entirely interfaces, it makes mocking or stubbing calls to my package (example, for testing) incredibly easy.

For this type of system to work, the methods on the struct (in this case, stringDoer) must be exported, even if the struct itself isn't.

Upvotes: 31

user94559
user94559

Reputation: 60143

This is the commit that unexports it: https://github.com/btcsuite/btcd/commit/7411e65b1e8d4e4c6da198590ad627bfe253173c. From the commit message:

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.

I believe you're correct that you (outside the package) cannot make use of this struct. It's used purely inside the package implementation.

Upvotes: 1

Related Questions