Best practice for "main.go" to access members of a structure in the real package

541 views
Skip to first unread message

Pat Farrell

unread,
Feb 18, 2023, 12:18:03 AM2/18/23
to golang-nuts
I'm still struggling with how to setup my access.
I'm building a library, say  tagtool   and it has a nice clean subdirectory with the files
that make up the go package, each with 

package tagtool

And I have a subdirectory called "cmd" that contains a near trivial main.go
that calls the various tagtool.Mumble() func.
So far, so good.

But I've been using file/package level vars. This is clearly a bad thing.
So I'm trying to bundle all the various vars into a struct, and 
I'll have my main.go call a 

func AllocateData() *GlobalVars {
    rval := new(GlobalVars)
    //.. do other init stuff
    return rval
}

This way we have the main holding the storage for what had been file/package level
vars.

Which is a good start. It works great if I capitalize all the variables.
But I really don't want to make all of the variables in the struct be part of my public API. They are all implementation details. I need to be able to initialize various variables in the GlobalVars struct from my 'main.go'

Right now, its mostly flag variables that I need. Stuff like
    flag.BoolVar(&flags.Debug, "de", false, "debug on")

The main.go doesn't really care about the values once the flag package has set them from the shell arguments, it just wants the tagtool 

Is there a "friend" declaration or import that lets the "package main" look into
the package tagtool?

Thanks
Pat

Jason Phillips

unread,
Feb 18, 2023, 8:20:53 AM2/18/23
to golang-nuts
There isn't a friend declaration but the Go tool does support a concept of "internal" packages since Go 1.4. Read about it here: https://go.dev/doc/go1.4#internalpackages

Marcin Romaszewicz

unread,
Feb 26, 2023, 7:46:48 PM2/26/23
to Pat Farrell, golang-nuts
Go doesn't have file scoped variables, only global variables and local variables declared in functions, so your "file" scope variables are global to their package.

Global variables aren't inherently bad, that's a bit of voodoo that some ideological languages introduced, and people believe without question.

Now, as for your particular example, I've handled this in a different way in my own code. Each of your packages can have a "RegisterFlags()" function which registers its own command line flags, and returns a struct containing the flags. You can implement another function called "InitFromFlags(flagStruct...)". This way, there's no global state, and package initialization is still decoupled from flags.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/d64ccb62-9134-4c66-8fb3-6ce1ffe19871n%40googlegroups.com.

Wojciech S. Czarnecki

unread,
Feb 27, 2023, 1:29:42 PM2/27/23
to golan...@googlegroups.com, Pat Farrell
Dnia 2023-02-17, o godz. 19:18:23
Pat Farrell <pat2...@gmail.com> napisał(a):

> Which is a good start. It works great if I capitalize all the variables.
> But I really don't want to make all of the variables in the struct be part
> of my public API.

then make GetSmth methods on that struct. That will be your public api.

> They are all implementation details. I need to be able to
> initialize various variables in the GlobalVars struct from my 'main.go'

If you use flags package you will have other fields exposed though.

I personally stopped use flags, due to too much chores around it.

Here is mine's substitute I prefer for simple cmd scripts:

https://github.com/ohir/mopt


> But I've been using file/package level vars. This is clearly a bad thing.

It is perfectly OK if these are set once from the cmdline.

Hope this helps,

--
Wojciech S. Czarnecki
<< ^oo^ >> OHIR-RIPE

(cc due to thread age)

Nagaev Boris

unread,
Feb 28, 2023, 4:45:27 AM2/28/23
to Wojciech S. Czarnecki, golan...@googlegroups.com, Pat Farrell
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/20230227192857.674ad274%40xmint.

I use github.com/jessevdk/go-flags
It allows you to define a struct with tags specifying command line
flags and environment variables and parse the list of arguments into
it:

type Config struct {
Foo string `long:"foo" env:"FOO" description:"The value of Foo"
default:"foo-default-value"`
}

var config Config
_, err := flags.Parse(&config)
if flags.WroteHelp(err) {
os.Exit(2)
} else if err != nil {
panic(err)
}
fmt.Println(config.Foo)

You can also use it in tests:
flags.ParseArgs(&config, []string{"--foo", "Some value"})

--
Best regards,
Boris Nagaev
Reply all
Reply to author
Forward
0 new messages