2 min read
Initialization of package variables
Thank you to everyone who responded to yesterday’s pop quiz! I got a number of responses, both by email, and on LinkedIn and Mastodon. And the majority of responses made the exact same mistake I made, and assumed the code was invalid, because a is referenced before it’s initialized: var x = a var a = 3 And while it’s true that this is an error within a function, much to my surprise, it’s actually completely valid in package scope, as we’ll see now.
1 min read
Pop quiz
It’s time for a pop quiz. Is the following code valid? var x = a var a = 3 Think about it. Hit reply with your answer, and explanation. I’ll provide a full answer and explanation tomorrow. Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)
2 min read
Zero values
I’m sorry for missing a couple days. We took an long weekend with some extended family to visit the beach here in Guatemala. But I’m back, and ready to talk about … zero values! Program initialization and execution The zero value When storage is allocated for a variable, either through a declaration or a call of new, or when a new value is created, either through a composite literal or a call of make, and no explicit initialization is provided, the variable or value is given a default value.
2 min read
An example package
Today we have something a bit different. Just a sample package. An example package Here is a complete Go package that implements a concurrent prime sieve. package main import "fmt" // Send the sequence 2, 3, 4, … to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'src' to channel 'dst', // removing those divisible by 'prime'.
Subscribe to Boldly Go: Daily
Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.
Unsure? Browse the archive.
2 min read
Blank imports & import side effects
Yesterday I promised to teach you the one dirty trick they don’t want you to know about, to get around Go’s restriction on circular imports. It’s explained in this sentence, the last from the spec on the topic of imports. Import declarations … To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name: import _ "lib/math" Did you catch it? It’s very subtle.
2 min read
Import cycles
First off, the spec provides an example of how to reference a symbol in an imported package, using different import alias options. I’ve already provided my own examples earlier, and it’s pretty straight forward, so we’ll just breeze through this part. Import declarations … Consider a compiled a package containing the package clause package math, which exports function Sin, and installed the compiled package in the file identified by "lib/math". This table illustrates how Sin is accessed in files that import the package after the various types of import declaration.
2 min read
Valid import paths
Today we’re looking at one of the more essoteric parts of the spec. Import declarations … Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to Unicode’s L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&’()*,:;<=>?[]^`{|} and the Unicode replacement character U+FFFD. Other than what’s stated in the quote, we’re not going to look at an exhaustive list of what is and isn’t guaranteed to be supported by a Go implementation.
2 min read
Relative imports
Newcomers to Go often try to use relative imports, and then are usually bitten by random weird problems. They seem to work sometimes, and not other times. What’s the deal? import "./foo" Import declarations … The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages. Okay. So this bit of the spec doesn’t help a whole lot.
1 min read
Working with versioned imports
We’re continuing today our discussion of imports. Yesterday we left off with using explicit package names in an import clause when the package name differs from the last element of the import path. Is that the only reason to explicitly name your imports? No. Sometimes you need to disambiguate between two imports with the same package name. Or maybe you just like a shorter name. import ( log "github.com/sirupsen/logrus" // Shorter names are nice stdlog "log" // Oh, but we need to reference this package, too ) There is one exception to the rule “Name your packages the same as the last element of your import path,” though: v2+ releases.
3 min read
Import declarations
Today we have a very important topic… Import declarations An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported. ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
4 min read
Packages
I’m back! I took an extra week off, from what I planned, due to chaotic circumstances, but I’m back again now. I’m also in a new timezone—America/Central. So my daily emails may begin coming on a different erratic schedule than the previous erratic schedule you were accustomed to. Anyway, let’s get back into the spec! If you’ve done any Go coding at all, you’ve seen at least one package, the main package.