Goroutines in Go are similar to threads in other languages in terms of usage. Internally, Go creates a number of threads (specified by GOMAXPROCS
) and then schedules the goroutines to run on the threads. Because of this design, Go's concurrency mechanisms are much more efficient than threads in terms of memory usage and initialization time.
Go provides a built-in map
type that implements a hash table. Maps are Go's built-in associative data type (also called hashes or dictionaries in other languages).
http.ServeMux
provides a multiplexer which calls handlers for HTTP requests.
Alternatives to the standard library multiplexer include:
Note how in Go you don't raise an error. Instead, you return an error in case of failure.
If a function can fail, the last returned value is generally an error
type.
// This method doesn't fail
func DoSomethingSafe() {
}
// This method can fail
func DoSomething() (error) {
}
// This method can fail and, when it succeeds,
// it returns a string.
func DoAndReturnSomething() (string, error) {
}
Vendoring is a method of ensuring that all of your 3rd party packages that you use in your Go project are consistent for everyone who develops for your application.
When your Go package imports another package, the compiler normally checks $GOPATH/src/
for the path of the imported project. However if your package contains a folder named vendor
, the compiler will check in that folder first. This means that you can import other parties packages inside your own code repository, without having to modify their code.
Vendoring is a standard feature in Go 1.6 and up. In Go 1.5, you need to set the environment variable of GO15VENDOREXPERIMENT=1
to enable vendoring.
The package "encoding/json"
Package json implements encoding and decoding of JSON objects in Go
.
Types in JSON along with their corresponding concrete types in Go are:
JSON Type | Go Concrete Type |
---|---|
boolean | bool |
numbers | float64 or int |
string | string |
null | nil |
Supported Operating System and Architecture target combinations (source)
$GOOS | $GOARCH |
---|---|
android | arm |
darwin | 386 |
darwin | amd64 |
darwin | arm |
darwin | arm64 |
dragonfly | amd64 |
freebsd | 386 |
freebsd | amd64 |
freebsd | arm |
linux | 386 |
linux | amd64 |
linux | arm |
linux | arm64 |
linux | ppc64 |
linux | ppc64le |
linux | mips64 |
linux | mips64le |
netbsd | 386 |
netbsd | amd64 |
netbsd | arm |
openbsd | 386 |
openbsd | amd64 |
openbsd | arm |
plan9 | 386 |
plan9 | amd64 |
solaris | amd64 |
windows | 386 |
windows | amd64 |
Go supports constants of character, string, boolean, and numeric values.
Interfaces in Go are just fixed method sets. A type implicitly implements an interface if its method set is a superset of the interface. There is no declaration of intent.
A channel holding the empty struct make(chan struct{})
is a clear message to the user that no information is transmitted over the channel and that it's purely used for synchronization.
Regarding unbuffered channels, a channel write will block until a corresponding read occurs from another goroutine. The same is true for a channel read blocking while waiting for a writer.
For a list of SQL database drivers see the official Go wiki article SQLDrivers.
The SQL drivers are imported and prefixed by _
, so that they are only available to driver.
Golang provides packages like:
text/template
html/template
to implement data-driven templates for generating textual and HTML outputs.
It is important to defer resp.Body.Close()
after every HTTP request that does not return a non-nil error, else resources will be leaked.
While many uses of the encoding/xml
package include marshaling and unmarshaling to a Go struct
, it's worth noting that this is not a direct mapping. The package documentation states:
Mapping between XML elements and data structures is inherently flawed: an XML element is an order-dependent collection of anonymous values, while a data structure is an order-independent collection of named values.
For simple, unordered, key-value pairs, using a different encoding such as Gob's or JSON may be a better fit. For ordered data or event / callback based streams of data, XML may be the best choice.
The reflect
docs are a great reference. In general computer programming, reflection is ability of a program to examine the structure and behavior of itself at runtime
.
Based on its strict static type
system Go lang has some rules (laws of reflection)
Build tags are used for conditionally building certain files in your code. Build tags may ignore files that you don't want build unless explicitly included, or some predefined build tags may be used to have a file only be built on a particular architecture or operating system.
Build tags may appear in any kind of source file (not just Go), but they must appear near the top of the file, preceded only by blank lines and other line comments. These rules mean that in Go files a build constraint must appear before the package clause.
A series of build tags must be followed by a blank line.
Inline expansion is a common optimization in compiled code that prioritized performance over binary size. It lets the compiler replace a function call with the actual body of the function; effectively copy/pasting code from one place to another at compile time. Since the call site is expanded to just contain the machine instructions that the compiler generated for the function, we don't have to perform a CALL or PUSH (the x86 equivalant of a GOTO statement or a stack frame push) or their equivalant on other architectures.
The inliner makes decisions about whether or not to inline a function based on a number of heuristics, but in general Go inlines by default. Because the inliner gets rid of function calls, it effectively gets to decide where the scheduler is allowed to preempt a goroutine.
Function calls will not be inlined if any of the following are true (there are many other reasons too, this list is incomplete):
...
args)panic
, recover
, or defer
The context
package (in Go 1.7) or the golang.org/x/net/context
package (Pre 1.7) is an interface for creating contexts that can be used to carry request scoped values and deadlines across API boundaries and between services, as well as a simple implementation of said interface.
aside: the word "context" is loosely used to refer to the entire tree, or to individual leaves in the tree, eg. the actual context.Context
values.
At a high level, a context is a tree. New leaves are added to the tree when they are constructed (a context.Context
with a parent value), and leaves are never removed from the tree. Any context has access to all of the values above it (data access only flows upwards), and if any context is canceled its children are also canceled (cancelation signals propogate downwards). The cancel signal is implemented by means of a function that returns a channel which will be closed (readable) when the context is canceled; this makes contexts a very efficient way to implement the pipeline and cancellation concurrency pattern, or timeouts.
By convention, functions that take a context have the first argument ctx context.Context
. While this is just a convention, it's one that should be followed since many static analysis tools specifically look for this argument. Since Context is an interface, it's also possible to turn existing context-like data (values that are passed around throughout a request call chain) into a normal Go context and use them in a backwards compatible way just by implementing a few methods. Furthermore, contexts are safe for concurrent access so you can use them from many goroutines (whether they're running on parallel threads or as concurrent coroutines) without fear.
Defer works by injecting a new stack frame (the called function after the defer
keyword) into the call stack below the currently executing function. This means that defer is guaranteed to run as long as the stack will be unwound (if your program crashes or gets a SIGKILL
, defer will not execute).
The iota
identifier is used to assign values to lists of constants. When iota is used in a list it starts with a value of zero, and increments by one for each value in the list of constants and is reset on each const
keyword. Unlike the enumerations of other languages, iota can be used in expressions (eg. iota + 1
) which allows for greater flexibility.
This article assumes knowledge of Defer Basics
For ordinary error handling, read the topic on error handling
The encoding/base64
package contains several built in encoders. Most of the examples in this document will use base64.StdEncoding
, but any encoder (URLEncoding
, RawStdEncodign
, your own custom encoder, etc.) may be substituted.
One thing to note - types that have a non-nil zero value like strings, ints, floats, bools and structs can't be set to nil.
Visit the Downloads List and find the right archive for your operating system. The names of these downloads can be a bit cryptic to new users.
The names are in the format go[version].[operating system]-[architecture].[archive]
For the version, you want to choose the newest available. These should be the first options you see.
For the operating system, this is fairly self-explanatory except for Mac users, where the operating system is named "darwin". This is named after the open-source part of the operating system used by Mac computers.
If you are running a 64-bit machine (which is the most common in modern computers), the "architecture" part of the file name should be "amd64". For 32-bit machines, it will be "386". If you're on an ARM device like a Raspberry Pi, you'll want "armv6l".
For the "archive" part, Mac and Windows users have two options because Go provides installers for those platforms. For Mac, you probably want "pkg". For Windows, you probably want "msi".
So, for instance, if I'm on a 64-bit Windows machine and I want to download Go 1.6.3, the download I want will be named:
go1.6.3.windows-amd64.msi
Now that we have a Go archive downloaded, we need to extract it somewhere.
Since installers are provided for these platforms, installation is easy. Just run the installer and accept the defaults.
There is no installer for Linux, so some more work is required. You should have downloaded a file with the suffix ".tar.gz". This is an archive file, similar to a ".zip" file. We need to extract it. We will be extracting the Go files to /usr/local
because it is the recommended location.
Open up a terminal and change directories to the place where you downloaded the archive. This is probably in Downloads
. If not, replace the directory in the following command appropriately.
cd Downloads
Now, run the following to extract the archive into /usr/local
, replacing [filename]
with the name of the file you downloaded.
tar -C /usr/local -xzf [filename].tar.gz
There's one more step to go before you're ready to start developing. We need to set environment variables, which is information that users can change to give programs a better idea of the user's setup.
You need to set the GOPATH
, which is the folder that you will be doing Go work in.
You can set environment variables through the "Environment Variables" button on the "Advanced" tab of the "System" control panel. Some versions of Windows provide this control panel through the "Advanced System Settings" option inside the "System" control panel.
The name of your new environment variable should be "GOPATH". The value should be the full path to a directory you'll be developing Go code in. A folder called "go" in your user directory is a good choice.
You need to set the GOPATH
, which is the folder that you will be doing Go work in.
Edit a text file named ".bash_profile", which should be in your user directory, and add the following new line to the end, replacing [work area]
with a full path to a directory you would like to do Go work in. If ".bash_profile" does not exist, create it. A folder called "go" in your user directory is a good choice.
export GOPATH=[work area]
Because Linux doesn't have an installer, it requires a bit more work. We need to show the terminal where the Go compiler and other tools are, and we need to set the GOPATH
, which is a folder that you will be doing Go work in.
Edit a text file named ".profile", which should be in your user directory, and add the following line to the end, replacing [work area]
with a full path tto a directory you would like to do Go work in. If ".profile" does not exist, create it. A folder called "go" in your user directory is a good choice.
Then, on another new line, add the following to your ".profile" file.
export PATH=$PATH:/usr/local/go/bin
If the Go tools are still not available to you in the terminal, try closing that window and opening a fresh terminal window.
For more in profiling go programs visit the go blog.
Caveats for build tags:
// +build
constraint must be placed at the top of the file, even before package clause.List of valid platforms for both build tags and file suffixes |
---|
android |
darwin |
dragonfly |
freebsd |
linux |
netbsd |
openbsd |
plan9 |
solaris |
windows |
Refer to $GOOS
list in https://golang.org/doc/install/source#environment for the most up-to-date platform list.
Interface can't be implemented with pointer receivers because *User
is not User
API Documentation
The Signature of middleware should be (http.ResponseWriter, *http.Request) i.e. of http.handlerFunc type.
There are two steps of using protobuf.
gRPC Support
If a proto file specifies RPC services, protoc-gen-go can be instructed to generate code compatible with gRPC (http://www.grpc.io/). To do this, pass the plugins
parameter to protoc-gen-go; the usual way is to insert it into the --go_out argument to protoc:
protoc --go_out=plugins=grpc:. *.proto
context.Context and HTTP middleware are outside the scope of this topic, but nonetheless those curious, wandering souls should check out https://github.com/goware/jwtauth, https://github.com/auth0/go-jwt-middleware, and https://github.com/dgrijalva/jwt-go.
Huge kudos to Dave Grijalva for his amazing work on go-jwt.