- put main.go in the root folder
- go mod init rootfoldername
- go run . to run
- Code:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
- go get github.com/rivo/tview@master
- Files dumped in $GOPATH/pkg/mod, which is usually ~/.go/pkg/mod
- Verify location with go env GOMODCACHE
- Reference the dependency in the code, eg: import "foo/bar"
- go mod tidy to remove anything no longer used.
Go file layouts are a bit unusual. Do like this:
- cmd/cmdname/main.go if a multi-executable project
- main.go if just a single executable project
- go.mod is the list of modules your code uses, along with the versions
- go.sum is the hashes of the modules, so your code is replicable on another machine.
go build -o exe-name
Years ago when I worked in Go, several idioms were mysteries that I used without really understanding them and I disliked Go because there was very little documentation at the time. Now with AI to query, the language is more enjoyable because there are fewer footguns to trip me up. Notable examples below..
map[int]struct{} - map creates a map (dictionary). They keys are ints and the values are struct{}s. struct{} is a 0-byte memory structure in Go. So this is a way to create a mapping that has keys but no values. The Go compiler essentially optimizes this down to a set.
You would store values in this map like m.mymap[2] = struct{}{}. Even though it appears as though you are storing something in the map, no value is stored, just the key.
msg.(type) here is referred to as a Type switch. It runs the switch statement on the type of the thing (the msg). So msg can be any type at runtime. In practice, msg must be an empty interface like interface{} that doesn't become a thing until called. x.(type) is only valid inside a switch statement. This is a workaround to handle dynamic types.