Three new books, Go Optimizations 101, Go Details & Tips 101 and Go Generics 101 are published now. It is most cost-effective to buy all of them through this book bundle in the Leanpub book store.

Go Details 101

Index:

A package can be imported more than once in a source file.

A Go source file can imports the same package multiple times, but the import names must be different. These same-package imports reference the same package instance.

For example:
package main

import "fmt"
import "io"
import inout "io"

func main() {
	fmt.Println(&inout.EOF == &io.EOF) // true
}

The default branch in switch and select blocks can be put before all case branches, after all case branches, or between case branches.

For example:
	switch n := rand.Intn(3); n {
	case 0: fmt.Println("n == 0")
	case 1: fmt.Println("n == 1")
	default: fmt.Println("n == 2")
	}

	switch n := rand.Intn(3); n {
	default: fmt.Println("n == 2")
	case 0: fmt.Println("n == 0")
	case 1: fmt.Println("n == 1")
	}

	switch n := rand.Intn(3); n {
	case 0: fmt.Println("n == 0")
	default: fmt.Println("n == 2")
	case 1: fmt.Println("n == 1")
	}

	var x, y chan int

	select {
	case <-x:
	case y <- 1:
	default:
	}

	select {
	case <-x:
	default:
	case y <- 1:
	}

	select {
	default:
	case <-x:
	case y <- 1:
	}

The numeric constant case expressions in a switch block can't be duplicate, but boolean ones can.

For example, the following program fails to compile.
package main

func main() {
	switch 123 {
	case 123:
	case 123: // error: duplicate case
	}
}
But the following program compiles okay.
package main

func main() {
	switch false {
	case false:
	case false:
	}
}

For reasons, please read this issue. The behavior is compiler dependent. In fact, the standard Go compiler also doesn't allow duplicate string case expressions, but gccgo allows.

The switch expressions in switch block are always evaluated to typed values.

For example, the switch expression 123 in the following switch block is viewed as a value of int instead of an untyped integer. So the following program fails to compile.
package main

func main() {
	switch 123 {
	case int64(123):  // error: mismatched types
	case uint32(789): // error: mismatched types
	}
}

The default switch expression of a switch block is a typed value true of the predeclared type bool.

For example, the following program will print true.
package main

import "fmt"

func main() {
	switch { // <=> switch true {
	case true:  fmt.Println("true")
	case false: fmt.Println("false")
	}
}

Sometimes, the open brace { of an explicit code block can be put on the next line.

For example:
package main

func main() {
	var i = 0
Outer:
	for
	{ // okay on the next line
		switch
		{ // okay on the next line
		case i == 5:
			break Outer
		default:
			i++
		}
	}
}

What result will the following program print? true or false? The answer is true. Please read line break rules in Go for reasons.
package main

import "fmt"

func False() bool {
	return false
}

func main() {
	switch False()
	{
	case true:  fmt.Println("true")
	case false: fmt.Println("false")
	}
}

Some case branch blocks must be explicit.

For example, the following program fails to compile.
func demo(n, m int) (r int) {
	switch n {
	case 123:
		if m > 0 {
			goto End
		}
		r++

		End: // syntax error: missing statement after label
	default:
		r = 1
	}
	return
}
To make it compile okay, the case branch code block should be explicit:
func demo(n, m int) (r int) {
	switch n {
	case 123: {
		if m > 0 {
			goto End
		}
		r++

		End:
	}
	default:
		r = 1
	}
	return
}
Alternatively, we can let a semicolon follow the label declaration End::
func demo(n, m int) (r int) {
	switch n {
	case 123:
		if m > 0 {
			goto End
		}
		r++

		End:;
	default:
		r = 1
	}
	return
}

Please read line break rules in Go for reasons.

A nested deferred function calls can modify return result values of its innermost nesting function.

For example:
package main

import "fmt"

func F() (r int) {
	defer func() {
		r = 789
	}()

	return 123 // <=> r = 123; return
}

func main() {
	fmt.Println(F()) // 789
}

Some recover calls may be no-ops.

We should call the recover function at the right places. Please read the right places to call the built-in recover function for details.

Exit a program with a os.Exit function call and exit a goroutine with a runtime.Goexit function call.

We can exit a program from any function by calling the os.Exit function. An os.Exit function call takes an int code as argument and returns the code to operating system.

An example:
// exit-example.go
package main

import "os"
import "time"

func main() {
	go func() {
		time.Sleep(time.Second)
		os.Exit(1)
	}()
	select{}
}
Run it:
$ go run a.go
exit status 1
$ echo $?
1

We can make a goroutine exit by calling the runtime.Goexit function. The runtime.Goexit function has no parameters.

In the following example, the Java word will not be printed.
package main

import "fmt"
import "runtime"

func main() {
	c := make(chan int)
	go func() {
		defer func() {c <- 1}()
		defer fmt.Println("Go")
		func() {
			defer fmt.Println("C")
			runtime.Goexit()
		}()
		fmt.Println("Java")
	}()
	<-c
}

The precedence of the increment operator ++ and the decrement -- is lower than the dereference operator * and the address-taking operator &, which are lower than the property selection operator . in selectors.

For example:
package main

import "fmt"

type T struct {
	x int
	y *int
}

func main() {
	var t T
	p := &t.x // <=> p := &(t.x)
	fmt.Printf("%T\n", p) // *int

	*p++ // <=> (*p)++
	*p-- // <=> (*p)--

	t.y = p
	a := *t.y // <=> *(t.y)
	fmt.Printf("%T\n", a) // int
}

The type deduction rule for the left untyped operand of a bit-shift operation depends on whether or not the right operand is a constant.

package main

func main() {
}

const M  = 2
// Compiles okay. 1.0 is deduced as an int value.
var _ = 1.0 << M

var N = 2
// Fails to compile. 1.0 is deduced as a float64 value.
var _ = 1.0 << N

Please read this article for reasons.

Values of two pointer types with different underlying types can be converted to each other if the base types of their underlying types share the same underlying type.

An example:
package main

type MyInt int64
type Ta    *int64
type Tb    *MyInt

func main() {
	var a Ta
	var b Tb

	// Direct conversion is not allowed.
	//a = Ta(b) // error

	// But indirect conversion is possible.
	y := (*MyInt)(b)
	x := (*int64)(y)
	a = x           // <=> the next line
	a = (*int64)(y) // <=> the next line
	a = (*int64)((*MyInt)(b))
	_ = a
}

Addresses of different zero-sized values may be equal, or not.

Whether or not the addresses of two zero-sized values are equal is compiler and compiler version dependent.
package main

import "fmt"

func main() {
	a := struct{}{}
	b := struct{}{}
	x := struct{}{}
	y := struct{}{}
	m := [10]struct{}{}
	n := [10]struct{}{}
	o := [10]struct{}{}
	p := [10]struct{}{}

	fmt.Println(&x, &y, &o, &p)

	// For the standard Go compiler (1.22.n),
	// x, y, o and p escape to heap, but
	// a, b, m and n are allocated on stack.

	fmt.Println(&a == &b) // false
	fmt.Println(&x == &y) // true
	fmt.Println(&a == &x) // false

	fmt.Println(&m == &n) // false
	fmt.Println(&o == &p) // true
	fmt.Println(&n == &p) // false
}

The outputs indicated in the above code are for the standard Go compiler 1.22.n.

The base type of a pointer type may be the pointer type itself.

An example:
package main

func main() {
	type P *P
	var p P
	p = &p
	p = **************p
}

Similarly,
  • the element type of a slice type can be the slice type itself,
  • the element type of a map type can be the map type itself,
  • the element type of a channel type can be the channel type itself,
  • and the argument and result types of a function type can be the function type itself.
package main

func main() {
	type S []S
	type M map[string]M
	type C chan C
	type F func(F) F

	s := S{0:nil}
	s[0] = s
	m := M{"Go": nil}
	m["Go"] = m
	c := make(C, 3)
	c <- c; c <- c; c <- c
	var f F
	f = func(F)F {return f}

	_ = s[0][0][0][0][0][0][0][0]
	_ = m["Go"]["Go"]["Go"]["Go"]
	<-<-<-c
	f(f(f(f(f))))
}

A detail about selector shorthands.

For a pointer value, which type is either named or not, if the base type of its (pointer) type is a struct type, then we can select the fields of the struct value referenced by the pointer value through the pointer value. However, if the type of the pointer value is a named type, then we can't select the methods of the struct value referenced by the pointer value through the pointer value.

package main

type T struct {
	x int
}
func (T) m(){} // T has one method.

type P *T  // a named one-level pointer type.
type PP *P // a named two-level pointer type.

func main() {
	var t T
	var tp = &t
	var tpp = &tp
	var p P = tp
	var pp PP = &p
	tp.x = 12  // okay
	p.x = 34   // okay
	pp.x = 56  // error: type PP has no field or method x
	tpp.x = 78 // error: type **T has no field or method x

	tp.m()  // okay. Type *T also has a "m" method.
	p.m()   // error: type P has no field or method m
	pp.m()  // error: type PP has no field or method m
	tpp.m() // error: type **T has no field or method m
}

Sometimes, nested composite literals can be simplified.

Please read nested composite literals can be simplified for details.

In some scenarios, it is ok to use array pointers as arrays.

Please read use array pointers as arrays for details.

Retrieving elements from nil maps will not panic. The result is a zero element value.

For example, the Foo1 and the Foo2 functions are equivalent, but the function Foo2 is much tidier than the function Foo1.
func Foo1(m map[string]int) int {
	if m != nil {
		return m["foo"]
	}
	return 0
}

func Foo2(m map[string]int) int {
	return m["foo"]
}

Deleting an entry from a nil map will not panic. It is a no-op.

For example, the following program will not panic.
package main

func main() {
	var m map[string]int // nil
	delete(m, "foo")
}

The result slice of an append function call may share some elements with the original slice, or not.

Please read append and delete container elements for details.

The length of a subslice may be larger than the base slice the subslice derives from.

For example,
package main

import "fmt"

func main() {
	s := make([]int, 3, 9)
	fmt.Println(len(s)) // 3
	s2 := s[2:7]
	fmt.Println(len(s2)) // 5
}

Please read derive slices from arrays and slices for details.

Deriving a subslice from a nil slice is ok if all the indexes used in the subslice expression are zero. The result subslice is also a nil slice.

For example, the following program will not panic at run time.
package main

import "fmt"

func main() {
	var x []int // nil
	a := x[:]
	b := x[0:0]
	c := x[:0:0]
	// Print three "true".
	fmt.Println(a == nil, b == nil, c == nil)
}

Please read derive slices from arrays and slices for details.

Ranging over a nil maps or a nil slices is ok, it is a no-op.

For example, the following program compiles okay.
package main

func main() {
	var s []int // nil
	for range s {
	}

	var m map[string]int // nil
	for range m {
	}
}

Range over a nil array pointer is ok if the second iteration variable is ignored or omitted.

For example, the following program will print 01234.
package main

import "fmt"

func main() {
	var a *[5]int // nil
	for i, _ := range a {
		fmt.Print(i)
	}
}

The length and capacity of a slice can be modified separately.

We can modify the length and capacity of a slice separately through the reflection way. Please read modify the length and capacity properties of a slice individually for details.

The indexes in slice and array composite literals must be constants and non-negative.

For example, the following code fails to compile.
var k = 1
// error: index must be non-negative integer constant
var x = [2]int{k: 1}
// error: index must be non-negative integer constant
var y = []int{k: 1}

Note, the keys in map composite literals are not required to be constants.

The constant indexes or keys in slice/array/map composite literals can't be duplicate.

For example, the following code fails to compile.
// error: duplicate index in array literal: 1
var a = []bool{0: false, 1: true, 1: true}
// error: duplicate index in array literal: 0
var b = [...]string{0: "foo", 1: "bar", 0: "foo"}
// error: duplicate key "foo" in map literal
var c = map[string]int{"foo": 1, "foo": 2}

This feature can be used to assert some conditions at compile time.

Elements of unaddressable arrays are also unaddressable, but elements of unaddressable slices are always addressable.

The reason is the elements of an array value and the array will be stored in the same memory block when the array is stored in memory. But the situation is different for slices.

An example:
package main

func main() {
	// Container composite literals are unaddressable.

	// It is ok to take slice literal element addresses.
	_ = &[]int{1}[0] // ok
	// Cannot take addresses of array literal elements.
	_ = &[5]int{}[0] // error

	// It is ok to modify slice literal elements.
	[]int{1,2,3}[1] = 9  // ok
	// Cannot modify array literal elements.
	[3]int{1,2,3}[1] = 9 // error
}

It is ok to derive subslices from unaddressable slices, but not ok from unaddressable arrays.

The reason is the same as the last detail.

An example:
package main

func main() {
	// Map elements are unaddressable in Go.

	// The following lines compile okay. Deriving
	// slices from unaddressable slices is allowed.
	_ = []int{6, 7, 8, 9}[1:3]
	var ms = map[string][]int{"abc": {0, 1, 2, 3}}
	_ = ms["abc"][1:3]

	// The following lines fail to compile. Deriving
	// slices from unaddressable arrays is not allowed.
	/*
	_ = [...]int{6, 7, 8, 9}[1:3] // error
	var ma = map[string][4]int{"abc": {0, 1, 2, 3}}
	_ = ma["abc"][1:3]  // error
	*/
}

Putting entries with NaN as keys to a map is like putting the entries in a black hole.

This reason is NaN != NaN, which is another detail will be described below. Before Go 1.12, the elements with NaN as keys can only be found out in a for-range loop, Since Go 1.12, the elements with NaN as keys can also be printed out by fmt.Print alike functions.
package main

import "fmt"
import "math"

func main() {
	var a = math.NaN()
	fmt.Println(a) // NaN

	var m = map[float64]int{}
	m[a] = 123
	v, present := m[a]
	fmt.Println(v, present) // 0 false
	m[a] = 789
	v, present = m[a]
	fmt.Println(v, present) // 0 false

	fmt.Println(m) // map[NaN:789 NaN:123]
	delete(m, a)   // no-op
	fmt.Println(m) // map[NaN:789 NaN:123]

	for k, v := range m {
		fmt.Println(k, v)
	}
	// the above loop outputs:
	// NaN 123
	// NaN 789
}

Please note, before Go 1.12, the two fmt.Println(m) calls both printed map[NaN:<nil> NaN:<nil>].

The capacity of the result slice of a conversion from a string to byte/rune slice may be larger than the length of the result slice.

We should not assume the length and the capacity of the result slice are always equal.

In the following example, if the last fmt.Println line is removed, the outputs of the two lines before it print the same value 5; otherwise, one print 5 and one print 8 (for the standard Go compiler 1.22.n).
package main

import "fmt"

func main() {
	s := "abcde"
	x := []byte(s)              // len(s) == 1
	fmt.Println(cap([]byte(s))) // 32
	fmt.Println(cap(x))         // 8
	fmt.Println(x)
}

Some buggy code will be written if we assume the length and the capacity of the result slice are always equal.

For a slice s, the loop for i = range s {...} is not equivalent to the loop for i = 0; i < len(s); i++ {...}.

The respective final values of the iteration variable i may be different for the two loops.
package main

import "fmt"

var i int

func fa(s []int, n int) int {
	i = n
	for i = 0; i < len(s); i++ {}
	return i
}

func fb(s []int, n int) int {
	i = n
	for i = range s {}
	return i
}

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(fa(s, -1), fb(s, -1)) // 6 5
	s = nil
	fmt.Println(fa(s, -1), fb(s, -1)) // 0 -1
}

The iteration order over maps is not guaranteed to be the same from one iteration to the next.

For example, the following program will not run infinitely:
package main

import "fmt"

func f(m map[byte]byte) string {
	bs := make([]byte, 0, 2*len(m))
	for k, v := range m {
		bs = append(bs, k, v)
	}
	return string(bs)
}

func main() {
	m := map[byte]byte{'a':'A', 'b':'B', 'c':'C'}
	s0 := f(m)
	for i := 1; ; i++{
		if s := f(m); s != s0 {
			fmt.Println(s0)
			fmt.Println(s)
			fmt.Println(i)
			return
		}
	}
}

Please note, the entries in the JSON marshal result on maps are sorted by their keys. And since Go 1.12, printing maps (with the print functions in the standard fmt package) also results sorted entries.

If a map entry is created during an iteration of the map, that entry may be iterated during the iteration or may be skipped.

A proof:
package main

import "fmt"

func main() {
	m := map[int]int{0: 0, 1: 100, 2: 200}
	r, n, i:= len(m), len(m), 0
	for range m {
		m[n] = n*100
		n++
		i++
	}
	fmt.Printf("%d new entries, iterate %d and skip %d\n",
		i, i - r, n - i,
	)
}

Thanks to Valentin Deleplace for the above two detail suggestions.

A multi-result function call can't mix with other expressions when the call is used as the sources in an assignment or the arguments of another function call.

Please read use function calls as expressions for details.

Some function calls are evaluated at compile time.

Please read some function calls are evaluated at compile time for details.

Each method corresponds to an implicit function.

Please read each Method Corresponds to an Implicit Function for details.

Comparing two interface values with the same dynamic incomparable type produces a panic.

For example:
package main

func main() {
	var x interface{} = []int{}
	_ = x == x // panic
}

Type assertions can be used to convert a value of an interface type to another interface type, even if the former interface type doesn't implement the latter one.

For example:
package main

type Foo interface {
	foo()
}

type T int
func (T) foo() {}

func main() {
	var x interface{} = T(123)
	// The following two lines fails to compile, for the
	// same reason: interface{} does not implement Foo.
	/*
	var _ Foo = x   // error
	var _ = Foo(x)  // error
	*/
	// But the following line compiles and runs okay.
	var _ = x.(Foo) // okay
}

Whether or not the second optional result of a type assertion is present will affect the behavior of the type assertion.

If the second optional result presents in a failed type assertion, the type assertion will not produce a panic. Otherwise, a panic will occur. For example:
package main

func main() {
	var x interface{} = true

	// Assertion fails, but doesn't cause a panic.
	_, _ = x.(int)

	// Assertion fails, which causes a panic.
	_ = x.(int)
}

About the impossible to-interface assertions which can be detected at compile time.

At compile time, some to-interface assertions can be deducted as impossible to succeed. For example, the assertion shown in the following code:
package main

type Ia interface {
	m()
}

type Ib interface {
	m() int
}

type T struct{}

func (T) m() {}

func main() {
	var x Ia = T{}
	_ = x.(Ib) // panic: main.T is not main.Ib
}

Such assertions will not make code compilations fail (but the program will panic at run time). Since Go Toolchain 1.15, the go vet command warns on such assertions.

Two error values returned by two errors.New calls with the same argument are not equal.

The reason is the errors.New function will copy the input string argument and use a pointer to the copied string as the dynamic value of the returned error value. Two different calls will produce two different pointers.
package main

import "fmt"
import "errors"

func main() {
	notfound := "not found"
	a, b := errors.New(notfound), errors.New(notfound)
	fmt.Println(a == b) // false
}

Receive-only channels can't be closed.

For example, the following code fails to compile.
package main

func main() {
}

func foo(c <-chan int) {
	close(c) // error: cannot close receive-only channel
}

Sending a value to a closed channel is viewed as a non-blocking operation, and this operation causes a panic.

For example, in the following program, when the second case branch gets selected, it will produce a panic at run time.
package main

func main() {
	var c = make(chan bool)
	close(c)
	select {
	case <-c:
	case c <- true: // panic: send on closed channel
	default:
	}
}

Types can be declared within function bodies.

Types can be declared in function bodies. For example,
package main

func main() {
	type T struct{}
	type S = []int
}

For the standard compiler, zero-sized fields in a struct may be treated as one-byte-sized value.

Please read this FAQ item for details.

NaN != NaN, Inf == Inf.

This follows IEEE-754 standard and is consistent with most other programming languages:
package main

import "fmt"
import "math"

func main() {
	var a = math.Sqrt(-1.0)
	fmt.Println(a)      // NaN
	fmt.Println(a == a) // false

	var x = 0.0
	var y = 1.0 / x
	var z = 2.0 * y
	fmt.Println(y, z, y == z) // +Inf +Inf true
}

Non-exported method names and struct field names from different packages are viewed as different names.

For example, if the following types are declared in package foo:
package foo

type I = interface {
	about() string
}

type S struct {
	a string
}

func (s S) about() string {
	return s.a
}
and the following types are declared in package bar:
package bar

type I = interface {
	about() string
}

type S struct {
	a string
}

func (s S) about() string {
	return s.a
}
then,
  • values of the two respective types S from the two packages can't be converted to each other.
  • the two respective interface types S from the two packages denote two distinct method sets.
  • type foo.S doesn't implement the interface type bar.I.
  • type bar.S doesn't implement the interface type foo.I.
package main

import "包2/foo"
import "包2/bar"

func main() {
	var x foo.S
	var y bar.S
	var _ foo.I = x
	var _ bar.I = y

	// The following lines fail to compile.
	x = foo.S(y)
	y = bar.S(x)
	var _ foo.I = y
	var _ bar.I = x
}

In struct value comparisons, blank fields will be ignored.

Blank fields are those fields whose name are the blank identifier _. The following program will print true.
package main

import "fmt"

type T struct {
	_ int
	_ bool
}

func main() {
	var t1 = T{123, true}
	var t2 = T{789, false}
	fmt.Println(t1 == t2) // true
}

Parentheses are required in several rare scenarios to make code compile okay.

For example:
package main

type T struct{x, y int}

func main() {
	// Each of the following three lines makes code
	// fail to compile. Some "{}"s confuse compilers.
	/*
	if T{} == T{123, 789} {}
	if T{} == (T{123, 789}) {}
	if (T{}) == T{123, 789} {}
	var _ = func()(nil) // nil is viewed as a type
	*/

	// We must add parentheses like the following
	// two lines to make code compile okay.
	if (T{} == T{123, 789}) {}
	if (T{}) == (T{123, 789}) {}
	var _ = (func())(nil) // nil is viewed as a value
}

Stack overflow is not panic.

For the current main stream Go compilers, stack overflows are fatal errors. Once a stack overflow happens, the whole program will crash without recovery ways.
package main

func f() {
	f()
}

func main() {
	defer func() {
		recover() // helpless to avoid program crashing
	}()
	f()
}
the running result:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
...

About more crash cases, please read this wiki article.

Some expression evaluation orders in Go are compiler implementation dependent.

Please read expression evaluation orders in Go for details.

The results of reflect.DeepEqual(x, y) and x == y may be different.

The function call reflect.DeepEqual(x, y) will always return false if the types of its two arguments are different, whereas x == y may return true even if the types of the two operands are different.

The second difference is a DeepEqual call with two pointer argument values of the same type returns whether or not the two respective values referenced by the two pointers are deep equal. So the call might return true even if the two pointers are not equal.

The third difference is the result of a DeepEqual call might return true if both of its arguments are in cyclic reference chains (to avoid infinite looping in the call).

The fourth difference is, the function call reflect.DeepEqual(x, y) is not expected to panic generally, whereas x == y will panic if the two operands are both interface values and their dynamic types are identical and incomparable.

An example showing these differences:
package main

import (
	"fmt"
	"reflect"
)

func main() {
	type Book struct {page int}
	x := struct {page int}{123}
	y := Book{123}
	fmt.Println(reflect.DeepEqual(x, y)) // false
	fmt.Println(x == y)                  // true

	z := Book{123}
	fmt.Println(reflect.DeepEqual(&z, &y)) // true
	fmt.Println(&z == &y)                  // false

	type Node struct{peer *Node}
	var q, r, s Node
	q.peer = &q // form a cyclic reference chain
	r.peer = &s // form a cyclic reference chain
	s.peer = &r
	println(reflect.DeepEqual(&q, &r)) // true
	fmt.Println(q == r)                // false

	var f1, f2 func() = nil, func(){}
	fmt.Println(reflect.DeepEqual(f1, f1)) // true
	fmt.Println(reflect.DeepEqual(f2, f2)) // false

	var a, b interface{} = []int{1, 2}, []int{1, 2}
	fmt.Println(reflect.DeepEqual(a, b)) // true
	fmt.Println(a == b)                  // panic
}

Note, if the two arguments of a DeepEqual call are both function values, then the call returns true only if the two function arguments are both nil and their types are identical. It is similar to compare container values whose elements contain function values or compare struct values whose fields contain function values. But please also note that the result of comparing two slices (of the same type) is always true if the two slices exactly share the same elements (in other words, they have the same length and each pair of their corresponding elements have the same address). An example:
package main

import (
	"fmt"
	"reflect"
)

func main() {
	a := [1]func(){func(){}}
	b := a
	fmt.Println(reflect.DeepEqual(a, a))       // false
	fmt.Println(reflect.DeepEqual(a[:], a[:])) // true
	fmt.Println(reflect.DeepEqual(a[:], b[:])) // false
	a[0], b[0] = nil, nil
	fmt.Println(reflect.DeepEqual(a[:], b[:])) // true
}

The reflect.Value.Bytes() method returns a []byte value, which element type, byte, might be not the same as the Go slice value represented by the receiver parameter.

Assume the underlying type of a defined type MyByte is the predeclared type byte, we know that Go type system forbids the conversions between []MyByte and []byte values. However, it looks the implementation of the method Bytes of the reflect.Value type partially violates this restriction unintentionally, by allowing converting a []MyByte value to []byte.

Example:
package main

import "bytes"
import "fmt"
import "reflect"

type MyByte byte

func main() {
	var mybs = []MyByte{'a', 'b', 'c'}
	var bs []byte

	// bs = []byte(mybs) // this line fails to compile

	v := reflect.ValueOf(mybs)
	bs = v.Bytes() // okay. Violating Go type system.
	fmt.Println(bytes.HasPrefix(bs, []byte{'a', 'b'})) // true

	bs[1], bs[2] = 'r', 't'
	fmt.Printf("%s \n", mybs) // art
}

But it looks the violation is not harmful. On the contrary, it makes some benefits. For example, with this violation, we can use the functions in the bytes standard package for the []MyByte values.

Note, the reflect.Value.Bytes() method might be removed later.

We should use os.IsNotExist(err) instead of err == os.ErrNotExist to check whether or not a file exists.

Using err == os.ErrNotExist may miss errors.
package main

import (
	"fmt"
	"os"
)

func main() {
	_, err := os.Stat("a-nonexistent-file.abcxyz")
	fmt.Println(os.IsNotExist(err))    // true
	fmt.Println(err == os.ErrNotExist) // false
}

For projects only supporting Go 1.13+, errors.Is(err, os.ErrNotExist) is more recommended to be used to check whether or not a file exists.
package main

import (
	"errors"
	"fmt"
	"os"
)

func main() {
	_, err := os.Stat("a-nonexistent-file.abcxyz")
	fmt.Println(errors.Is(err, os.ErrNotExist)) // true
}

The flag standard package treats boolean command flags differently than integer and string flags.

There are three forms to pass flag options.
  1. -flag, for boolean flags only.
  2. -flag=x, for any flag.
  3. -flag x, for non-boolean flags only.

And please note that, a boolean flag with the first form is viewed as the last flag, all items following it are viewed as arguments.

package main

import "fmt"
import "flag"

var b = flag.Bool("b", true, "a boolean flag")
var i = flag.Int("i", 123, "an integer flag")
var s = flag.String("s", "hi", "a string flag")

func main() {
	flag.Parse()
	fmt.Print("b=", *b, ", i=", *i, ", s=", *s, "\n")
	fmt.Println("arguments:", flag.Args())
}

If we run this program with the below shown flags and arguments
./exampleProgram -b false -i 789 -s bye arg0 arg1
the output will be
b=true, i=123, s=hi
arguments: [false -i 789 -s bye arg0 arg1]

This output is obviously not what we expect.

We should pass the flags and arguments like
./exampleProgram -b=false -i 789 -s bye arg0 arg1
or
./exampleProgram -i 789 -s bye -b arg0 arg1
to get the output we expect:
b=true, i=789, s=bye
arguments: [arg0 arg1]

[Sp|Fp|P]rintf functions support positional arguments.

The following program will print coco.
package main

import "fmt"

func main() {
	// The next line prints: coco
	fmt.Printf("%[2]v%[1]v%[2]v%[1]v", "o", "c")
}


Index↡

The Go 101 project is hosted on Github. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.

If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @go100and1.

The digital versions of this book are available at the following places:
Tapir, the author of Go 101, has been on writing the Go 101 series books and maintaining the go101.org website since 2016 July. New contents will be continually added to the book and the website from time to time. Tapir is also an indie game developer. You can also support Go 101 by playing Tapir's games (made for both Android and iPhone/iPad):
Individual donations via PayPal are also welcome.

Index: