default branch in switch and select blocks can be put before all case branches, after all case branches, or between case branches.
switch block can't be duplicate, but boolean ones can.
switch block are always evaluated to typed values.
switch block is a typed value true of the predeclared type bool.
{ of an explicit code block can be put on the next line.
case branch blocks must be explicit.
recover calls may be no-ops.
os.Exit function call and exit a goroutine with a runtime.Goexit function call.
++ and the decrement -- is lower than the dereference operator * and the address-taking operator &, which are lower than the property selection operator . in selectors.
append function call may share some elements with the original slice, or not.
NaN as keys to a map is like putting the entries in a black hole.
s, the loop for i = range s {...} is not equivalent to the loop for i = 0; i < len(s); i++ {...}.
error values returned by two errors.New calls with the same argument are not equal.
reflect.DeepEqual(x, y) and x == y may be different.
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.
os.IsNotExist(err) instead of err == os.ErrNotExist to check whether or not a file exists.
flag standard package treats boolean command flags differently than number and string flags.
[Sp|Fp|P]rintf functions support positional arguments.
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
}
default branch in switch and select blocks can be put before all case branches, after all case branches, or between case branches. 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:
}
switch block can't be duplicate, but boolean ones can.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.
switch block are always evaluated to typed values.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
}
}
switch block is a typed value true of the predeclared type bool.true.
package main
import "fmt"
func main() {
switch { // <=> switch true {
case true: fmt.Println("true")
case false: fmt.Println("false")
}
}
{ of an explicit code block can be put on the next line.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")
}
}
case branch blocks must be explicit.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.
package main
import "fmt"
func F() (r int) {
defer func() {
r = 789
}()
return 123 // <=> r = 123; return
}
func main() {
fmt.Println(F()) // 789
}
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.
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.
// 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.
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
}
++ and the decrement -- is lower than the dereference operator * and the address-taking operator &, which are lower than the property selection operator . in selectors.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
}
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.
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
}
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.20),
// 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.20.
package main
func main() {
type P *P
var p P
p = &p
p = **************p
}
Similarly,
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))))
}
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
}
Please read nested composite literals can be simplified for details.
Please read use array pointers as arrays for details.
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"]
}
package main
func main() {
var m map[string]int // nil
delete(m, "foo")
}
append function call may share some elements with the original slice, or not.Please read append and delete container elements for details.
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.
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.
package main
func main() {
var s []int // nil
for range s {
}
var m map[string]int // nil
for range m {
}
}
01234.
package main
import "fmt"
func main() {
var a *[5]int // nil
for i, _ := range a {
fmt.Print(i)
}
}
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.
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.
// 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.
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
}
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
*/
}
NaN as keys to a map is like putting the entries in a black hole.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>].
We should not assume the length and the capacity of the result slice are always equal.
In the following example, if the lastfmt.Println line is removed,
the outputs of the two lines before it print the same value 32,
otherwise, one print 32 and one print 8
(for the standard Go compiler 1.20).
package main
import "fmt"
func main() {
s := "a"
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.
s, the loop for i = range s {...} is not equivalent to the loop for i = 0; i < len(s); i++ {...}.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
}
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.
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.
Please read use function calls as expressions for details.
Please read some function calls are evaluated at compile time for details.
Please read each Method Corresponds to an Implicit Function for details.
package main
func main() {
var x interface{} = []int{}
_ = x == x // panic
}
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
}
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)
}
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.
error values returned by two errors.New calls with the same argument are not equal.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
}
package main
func main() {
}
func foo(c <-chan int) {
close(c) // error: cannot close receive-only channel
}
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:
}
}
package main
func main() {
type T struct{}
type S = []int
}
Please read this FAQ item for details.
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
}
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,
S from the two packages
can't be converted to each other.
S from the two packages
denote two distinct method sets.
foo.S doesn't implement the interface type bar.I.
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
}
_.
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
}
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
}
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.
Please read expression evaluation orders in Go for details.
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.
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
}
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.
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.
os.IsNotExist(err) instead of err == os.ErrNotExist to check whether or not a file exists.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
}
flag standard package treats boolean command flags differently than integer and string flags.-flag, for boolean flags only.
-flag=x, for any flag.
-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.coco.
package main
import "fmt"
func main() {
// The next line prints: coco
fmt.Printf("%[2]v%[1]v%[2]v%[1]v", "o", "c")
}
The Go 101 프로젝트는 Github 에서 호스팅됩니다. 오타, 문법 오류, 부정확한 표현, 설명 결함, 코드 버그, 끊어진 링크와 같은 모든 종류의 실수에 대한 수정 사항을 제출하여 Go 101을 개선을 돕는 것은 언제나 환영합니다.
주기적으로 Go에 대한 깊이 있는 정보를 얻고 싶다면 Go 101의 공식 트위터 계정인 @go100and1을 팔로우하거나 Go 101 슬랙 채널에j가입해주세요.
reflect 표준 패키지sync 표준 패키지sync/atomic 표준 패키지nil