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
-
Halcyon Creates Anti-Ransomware Protection for Linux
As more Linux systems are targeted by ransomware, Halcyon is stepping up its protection.
-
Valve and Arch Linux Announce Collaboration
Valve and Arch have come together for two projects that will have a serious impact on the Linux distribution.
-
Hacker Successfully Runs Linux on a CPU from the Early ‘70s
From the office of "Look what I can do," Dmitry Grinberg was able to get Linux running on a processor that was created in 1971.
-
OSI and LPI Form Strategic Alliance
With a goal of strengthening Linux and open source communities, this new alliance aims to nurture the growth of more highly skilled professionals.
-
Fedora 41 Beta Available with Some Interesting Additions
If you're a Fedora fan, you'll be excited to hear the beta version of the latest release is now available for testing and includes plenty of updates.
-
AlmaLinux Unveils New Hardware Certification Process
The AlmaLinux Hardware Certification Program run by the Certification Special Interest Group (SIG) aims to ensure seamless compatibility between AlmaLinux and a wide range of hardware configurations.
-
Wind River Introduces eLxr Pro Linux Solution
eLxr Pro offers an end-to-end Linux solution backed by expert commercial support.
-
Juno Tab 3 Launches with Ubuntu 24.04
Anyone looking for a full-blown Linux tablet need look no further. Juno has released the Tab 3.
-
New KDE Slimbook Plasma Available for Preorder
Powered by an AMD Ryzen CPU, the latest KDE Slimbook laptop is powerful enough for local AI tasks.
-
Rhino Linux Announces Latest "Quick Update"
If you prefer your Linux distribution to be of the rolling type, Rhino Linux delivers a beautiful and reliable experience.