So far I’ve been running all my code either in the Go Tour sandbox, using Go Playground, or from a single file in VS Code. My explorations in the previous article ended up with a a source file that was starting to get a little bit unwieldily, so let’s take a look at how that can be improved.
Within my most recent code, I have the main
function and the doProduce
function, which is fine when collapsed down:
But as soon as it’s not starts to get a bit long, so let’s split that out into its own file.
The Go docs have a whole section devoted to organising code, but I found it hard to follow. Part of it is probably because I’ve been living in VSCode and not using the Go environment with modules etc as the docs describe. This article helped clarify things a bit for me. Having played around I think I understand it a bit better now, thus:
-
If all you want to do is split a Go code file into separate ones, put them all in the same folder with the same package name and use
go run .
to execute them (or continue to run them from within your IDE such as VSCode) -
Files in the same folder with the same package name share access to their functions
-
You don’t have to do anything with
import
or modules, or anything like that. -
Leave
package main
alone - you come to change the package name when you’re actually building a package for import elsewhere-
At some point you probably should, and I’ll get onto that another time when I need to :)
-
So I started with the same file as previously, but in a new folder and new name:
➜ ls -l listener_test_01
total 24
-rw-r--r-- 1 rmoff staff 5256 16 Jul 11:17 main.go
From there I split doProduce
into its own source file, giving us:
➜ ls -l listener_test_01
total 32
-rw-r--r-- 1 rmoff staff 741 16 Jul 11:44 main.go
-rw-r--r-- 1 rmoff staff 4595 16 Jul 11:44 producer.go
The main.go
file includes main()
which then calls other functions
-
main.go
package main import ( "fmt" "os" ) func main() { if e := doProduce(broker, topic); e != nil { fmt.Printf("\nThere was a problem calling the producer :-(\n%v", e) } else { fmt.Println("Oh joy! Oh rejoice! Calling the producer worked *just fine*.") }
-
producer.go
package main import ( "errors" "fmt" "time" "gopkg.in/confluentinc/confluent-kafka-go.v1/kafka" ) // Produce a test message to given broker and topic func doProduce(broker, topic string) error { // -- // Create Producer instance
If you try to just run the main.go
file you’ll get
➜ go run main.go
# command-line-arguments
./main.go:26:10: undefined: doProduce
So instead you use this (h/t):
➜ go run *.go
Alternatively you can use
➜ go run .
Building a binary executable
Instead of compiling and running the code each time with go run
, you can also build a binary executable which can then be invoking directly. For this simply run:
go build
This builds an executable that takes the name of the parent folder by default
➜ ls -l listener_test_01
-rwxr-xr-x 1 rmoff staff 6.6M 16 Jul 15:30 listener_test_01
-rw-r--r-- 1 rmoff staff 741B 16 Jul 15:01 main.go
-rw-r--r-- 1 rmoff staff 4.5K 16 Jul 15:01 producer.go
Now you can run it directly, passing commandline arguments as needed
./listener_test_01 localhost:9092
What about go.mod
that you may have seen kicking about? For my very simple example here all it does is change the name of the executable that we build
➜ go mod init listenertest
go: creating new go.mod: module listenertest
➜ go build
➜ ll
total 27264
-rwxr-xr-x 1 rmoff staff 6.6M 16 Jul 15:37 listenertest