Harder than scripting, but easier than programming in C
Batteries Included
The all-inclusive binaries that the Go compiler produces turn out to be really useful. For example, if you want to run a Go program on a shared server offered by your favorite budget hoster, you simply compile it in peace on your home machine, even in a Docker container (or on a Mac if you are so fancy), and upload a single file that runs there, without a murmur of protest. No pestering about dependencies, no problems with shared libraries or additional modules that you need to install, and, of course, you won't need root privileges.
This may seem like a solution to a relatively trivial problem. But if you have ever tried to install a DIY Python script for a customer who either didn't have the right Python version, didn't have all the required packages, or perhaps even didn't have an Internet connection to make up for this missing infrastructure, you'll welcome a single ready-to-run binary as a savior.
If you distribute your software publicly and want to save users the trouble of compiling from the Go source code, you can also offer a binary for download on a website. Mind you, just one binary for all Linux variants – and then maybe one for macOS and maybe even a third one for the ARM-based Raspberry Pi. The build machine doesn't even have to run the target platform's architecture. If you want to create a Linux binary on the Mac, you do it with:
GOOS=linux GOARCH=386 go build ...
because Go supports cross-compiling perfectly. It can even create Windows binaries.
Although Go binaries naturally occupy more disk space than dynamically linked programs, compared to a 16TB hard disk, a 2MB "Hello World" binary in Go seems pretty insignificant – especially compared to the dependency hell the installer would inevitably have to descend into.
Draw from GitHub
A language does not live on its core alone. It is also important for as many volunteers as possible to continuously write new extensions and make them freely available to the community. This may sound crazy, but Go can actually reference third-party libraries from code repositories such as GitHub directly from the Go code. The compiler then fetches the source code through the network directly from the original server, along with the dependent packages. For example, Listing 2 uses the progressbar library on GitHub, which draws a beautiful progress bar in the terminal window. In its import
section, the program references the project's GitHub page and assigns it the (optional) pb
short form.
Listing 2
pb.go
01 package main 02 03 import ( 04 pb "github.com/schollz/progressbar/v3" 05 "time" 06 ) 07 08 func main() { 09 bar := pb.Default(100) 10 for i := 0; i < 100; i++ { 11 bar.Add(1) 12 time.Sleep(400 * time.Millisecond) 13 } 14 }
Faced with the spontaneous go build
of Listing 2, however, the Go compiler would grumble about the missing library, but a preceding go get
with the GitHub path listed in the code brings in the progress bar source. Instead of calling go get
, however, many developers today define a Go module instead with
go mod init NAME
which remembers dependencies in a newly created go.mod
file. A subsequent go build
handles the task of fetching the new code, including its dependencies, and linking it all to the existing code in one fell swoop.
Figure 1 shows that the code from Listing 2 compiles smoothly after creating a new Go module. The subsequent go build
call succeeds because the compiler drags in a version of the progressbar library directly from GitHub. Imagine the possibilities: Just about anybody can park new Go libraries on GitHub to share them with the world, and the world can just as easily access them at compile time.
Attentive readers will notice that this approach simply postpones the dependency hell problem from installation time to compilation time. If Go code relies on open source projects on GitHub, a binary that has been compiled once will always continue to run and can also be reinstalled without any problems. The build process for new versions, however, could encounter a problem if the library author mothballs their GitHub project or makes non-backward compatible changes: That would pull out the support for the user projects relying on the library.
Native JSON
System components often communicate over the network using data in JSON format. Go also takes this approach, packaging its data structures into JSON and unfolding them at the receiving end without any hitches. Naturally, as a rule of thumb in JSON, typed data chafes against Go's strict type model, but Go is to some extent lenient here.
Listing 3 first defines a keyVal
data structure with three components A
through c
, each containing a string as its value. To allow the Go code to access the struct's fields outside the current package
scope, the field names begin with a capital letter. JSON, on the other hand, traditionally uses lowercase keys in its data structures. This requires some back-and-forth conversions between Go internal variables and their JSON counterparts.
Listing 3
json.go
package main import ( "encoding/json" "fmt" ) type keyVal struct { A string `json:a` B string `json:b` C string `json:c` } func main() { jsonStr := []byte(`{"a": "x", "b": "y", "d": "z"}`) data := keyVal{} err := json.Unmarshal(jsonStr, &data) if err != nil { panic(err) } fmt.Printf("data=%+v\n", data) }
Mapping of the Go struct member names to the JSON names is driven by the backticked text following the field definition. An entry such as
A string `json:a`
specifies that the A
member of the Go structure of type KeyVal
is a string that arrives as a
in JSON.
The Go receiver responds quite flexibly to variations in the JSON data. If a value arrives in JSON under a key that the receiving Go struct does not define, the json.Unmarshal()
read function simply ignores it. Conversely, if the Go struct contains an entry that does not exist in the incoming JSON, Go leaves the structure field uninitialized.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs
-
Juno Computers Launches Another Linux Laptop
If you're looking for a powerhouse laptop that runs Ubuntu, the Juno Computers Neptune 17 v6 should be on your radar.