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
}
}
package main
func main() {
switch false {
case false:
case false:
}
}
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++
}
}
}
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
}
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
}
End:
:
func demo(n, m int) (r int) {
switch n {
case 123:
if m > 0 {
goto End
}
r++
End:;
default:
r = 1
}
return
}
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.
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.
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{}
}
$ go run a.go exit status 1 $ echo $? 1
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
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.24.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
}
package main
func main() {
type P *P
var p P
p = &p
p = **************p
}
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))))
}
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
}
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.
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
}
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)
}
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)
}
}
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}
// 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}
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
}
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
}
fmt.Println(m)
calls both printed map[NaN:<nil> NaN:<nil>]
.
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.24.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)
}
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
}
}
}
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,
)
}
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
}
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
}
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
}
bar
:
package bar
type I = interface {
about() string
}
type S struct {
a string
}
func (s S) about() string {
return s.a
}
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()
}
runtime: goroutine stack exceeds 1000000000-byte limit fatal error: stack overflow runtime stack: ...
reflect.DeepEqual(x, y)
and x == y
may be different.
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.
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.
DeepEqual
call might return true
if both of its arguments are in cyclic reference chains (to avoid infinite looping in the 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
}
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.
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
}
bytes
standard package for the []MyByte
values.
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
}
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.
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())
}
./exampleProgram -b false -i 789 -s bye arg0 arg1
b=true, i=123, s=hi arguments: [false -i 789 -s bye arg0 arg1]
./exampleProgram -b=false -i 789 -s bye arg0 arg1
./exampleProgram -i 789 -s bye -b arg0 arg1
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 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 @zigo_101.
reflect
standard package.sync
standard package.sync/atomic
standard package.