Skip to content

Instantly share code, notes, and snippets.

@justdoit0823
Last active August 22, 2018 07:08
Show Gist options
  • Save justdoit0823/1956b1db9719df31b5ffbabfb5e5ac99 to your computer and use it in GitHub Desktop.
Save justdoit0823/1956b1db9719df31b5ffbabfb5e5ac99 to your computer and use it in GitHub Desktop.
Golang essence.

Code organization

Overview

  • Go programmers typically keep all their Go code in a single workspace.
  • A workspace contains many version control repositories (managed by Git, for example).
  • Each repository contains one or more packages.

Workspace

A workspace is a directory hierarchy with three directories at its root:

  • src contains Go source files,
  • pkg contains package objects, and
  • bin contains executable commands.

Package

Each package consists of one or more Go source files in a single directory. The path to a package's directory determines its import path.

Data

Values

Arrays

Arrays are useful when planning the detailed layout of memory and sometimes can help avoid allocation.

  • Arrays are values. Assigning one array to another copies all the elements.
  • In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it.
  • The size of an array is part of its type. The types [10]int and [20]int are distinct.

Read more detail at arrays.

References

Slice

Slices wrap arrays to give a more general, powerful, and convenient interface to sequences of data. Slices hold references to an underlying array, and if you assign one slice to another, both refer to the same array. If a function takes a slice argument, changes it makes to the elements of the slice will be visible to the caller, analogous to passing a pointer to the underlying array.

Read more detail at slice.

Maps

Maps are a convenient and powerful built-in data structure that associate values of one type (the key) with values of another type (the element or value). Like slices, maps hold references to an underlying data structure. If you pass a map to a function that changes the contents of the map, the changes will be visible in the caller.

Read more detail at maps.

Channels

Like maps, channels are allocated with make, and the resulting value acts as a reference to an underlying data structure. If an optional integer parameter is provided, it sets the buffer size for the channel. The default is zero, for an unbuffered or synchronous channel. Unbuffered channels combine communication—the exchange of a value—with synchronization—guaranteeing that two calculations (goroutines) are in a known state.

Read more detail at channel.

Memory

Stack or heap

Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language.

Read more detail at stack_or_heap.

Allocation

New

new allocates memory, but unlike its namesakes in some other languages it does not initialize the memory, it only zeros it. That is, new(T) allocates zeroed storage for a new item of type T and returns its address, a value of type *T. In Go terminology, it returns a pointer to a newly allocated zero value of type T.

Read more detail at new.

Make

The built-in function make(T, args) serves a purpose different from new(T). It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T).

Constructors and composite literals

The composite literal is an expression that creates a new instance each time it is evaluated. The fields of a composite literal are laid out in order and must all be present. Besides, by labeling the elements explicitly as field:value pairs, the initializers can appear in any order, with the missing ones left as their respective zero values. it's easy to initialize value of any fields.

Read more detail at composite_literals.

Memory order

Within a single goroutine, reads and writes must behave as if they executed in the order specified by the program. That is, compilers and processors may reorder the reads and writes executed within a single goroutine only when the reordering does not change the behavior within that goroutine as defined by the language specification. Because of this reordering, the execution order observed by one goroutine may differ from the order perceived by another. Reads and writes of values larger than a single machine word behave as multiple machine-word-sized operations in an unspecified order.

Read more detail at memory.

Function

Parameters

As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter.

Read more detail at pass_by_value.

Method

A method is a function with a receiver.

Interfaces

Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here. A type can implement multiple interfaces.

Define method on values or pointers

When defining a method on a type, the receiver behaves exactly as if it were an argument to the method. Whether to define the receiver as a value or as a pointer is the same question, then, as whether a function argument should be a value or a pointer.

Read more detail at values_or_pointers.

Defer vesus goroutine

Defer

The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes. Besides avoiding worries about variables changing values as the function executes, this means that a single deferred call site can defer multiple function executions.

Read more detail at defer.

Goroutine

In Go, function literals are closures: the implementation makes sure the variables referred to by the function survive as long as they are active.

Read more detail at goroutine.

Synchronize

Channel

  • Unbuffered channel

Unbuffered channels combine communication—the exchange of a value—with synchronization—guaranteeing that two calculations (goroutines) are in a known state. If the channel is unbuffered, the sender blocks until the receiver has received the value.

  • Buffered channel

A buffered channel can be used like a semaphore, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.

Receivers always block until there is data to receive.

Read more detail at channel.

Mutex

A Mutex is a mutual exclusion lock. The zero value for a Mutex is an unlocked mutex. A locked Mutex is not associated with a particular goroutine.

It is allowed for one goroutine to lock a Mutex and then arrange for another goroutine to unlock it.

Reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment