nil* to obintain value, & to get address of a variablei, j := 42, 2701
p := &i // point to i, or =var p *int = &i=
*p = 21
p = &j
*p = *p / 37
(*p).X -> p.Xv = Vertex{X: 1}type Vertex struct {
X int
Y int
}
func main() {
v := &Vertex{1, 2}
v.X = 4
}
var a[10]int declare an int arrayvar a[2]string
a[0] = "Hello"
a[1] = "World"
primes := [6]int{2, 3, 5, 7, 11, 13}
// or primes := [...]int{2, 3, 5, 7, 11, 13}
zero value is nil
declare: letters := []string{"a", "b", "c", "d"}
can created by func make([]T, len, cap) []T, cap is optional, default same with len
var s []byte
s = make([]byte, 5, 5)
// s == []byte{0, 0, 0, 0, 0}
slice can be “slicing” of a slice or an array: a[1:3], half open
a slice doesn’t store data, only a reference to orginal array, change data will affect array
capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s) // len=6 cap=6 [2 3 5 7 11 13]
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s) // len=0 cap=6 []
// Extend its length.
s = s[1:4]
printSlice(s) // len=3 cap=5 [3 5 7]
// Drop its first two values.
s = s[2:]
printSlice(s) // len=1 cap=3 [7]
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
Growing capacity
manually
t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
for i := range s {
t[i] = s[i]
}
s = t
use func copy(dst, src []T) int
t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t
Append data
use func append(s []T, x ...T) []T
append adds data to a slice and increase capacity if necessary
a := make([]int, 1) // a == []int{0}
a = append(a, 1, 2, 3) // a == []int{0, 1, 2, 3}
aa := []string{"John", "Paul"}
b := []string{"George", "Ringo", "Pete"}
aa = append(aa, b...) // equivalent to "append(aa, b[0], b[1], b[2])"
// aa == []string{"John", "Paul", "George", "Ringo", "Pete"}
Some usecases
use in passing arguments, to avoid coping whole array
filter, declare an empty slice and append data to it
// Filter returns a new slice holding only the elements of s that satisfy fn()
func Filter(s []int, fn func(int) bool) []int {
var p []int // == nil
for _, v := range s {
if fn(v) {
p = append(p, v)
}
}
return p
}
replace array to save memory
func CopyDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
c := []byte
c = append(c, digitRegexp.Find(b))
return c
}
If just return digitRegexp.Find(b), the array b will not be released.
iterate over a slice or map
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
v += 1
fmt.Printf("2**%d = %d\n", i, v)
}
map keys to values
nil, no keys and nor can keys be addeduse make to create a map
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
or use literal to create a map
var m = map[string]Vertex{
"Bell Labs": Vertex{40.68433, -74.39967,},
"Google": {37.42202, -122.08408,},
}
func main() {
m["1"] = Vertex{1, 2}
fmt.Println(m)
}
m[key] = elemelem = m[key], if not exist, return key type’s zero valueelem, exist := m[key], if exist, exist==truedelete(m, key)functions are also values which can be passed as arguments or assined to variables
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
A closure is a function value that references variables from outside its body
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
type NewType float64type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
This is equal to:
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Use pointer receivers *T passing reference of the same object to functions to directly modify the same object
Methods with pointer receivers can eithered be called with a variable or a pointer
var v Vertex
v.Scale(5) // OK
p := &v
p.Scale(10) // OK
Methods with value receivers also take either a value or a pointer
(value, type), holding a value of a specific concrete typetype I interface {
M()
}
type T struct {
S string
}
// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()
}
Interface value can have nil underlying value and can call methods, concrete type’s nil value can not
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
i.M() // output: <nil>
// T.M() // compile error
}
Call a nil interface value will cause runtime error
Empty Interface An empty interface can hold values of any type Usually used where need to handle values of unknown type
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
Type assertions
t := i.(T)i holds a T, return that valuet, ok := i.(T)i holds a T, return that value and trueType switch
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
defined by fmt package
type Stringer interface {
String() string
}
type implements String method can print custom strings by fmt.Println
error is a built-in interfacetype error interface {
Error() string
}
error denotes success; non-nil denotes failuretype ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
return fmt.Sprintf("cannot Sqrt negative number: %f", float64(e))
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return 0, ErrNegativeSqrt(x)
}
...
return z, nil
}
io.Reader interface has a Read method:
func (T) Read(b []byte) (n int, err error)
it will return io.EOF when stream ends
A goroutine is a lightweight thread, running in the same address space
go f(x, y, z) starts a new goroutine
Like pipe, receive and send values use channel operator <-
Created before use: ch := make(chan int, <buffer size>)
By default, receive and send block until the other side is ready usually used to sync routines
// get sum of a array using two routines
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
Channel can be closed by sender
Receiver can get channel status by v, ok := <- ch
Loop for i:= range c receives values until c is closed
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
Select lets a goroutine execute a case which is ready, or pick one randomly if all cases are ready
if default case exists, Select will execute it when no channels are ready
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
Lock and Unlock in sync.Mutex// SafeCounter is safe to use concurrently.
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key]++
c.mux.Unlock()
}
// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}
{} is always requiredfor i := 0; i < 10; i++ {
sum += i
}
for ; sum < 1000; {
sum += sum
}
for sum < 1000 {
sum += sum
}
for {
}
{} is always requiredif v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
break is not needed in each casecase can be any valuecase evaluated from top to bottomswitch trueswitch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd, plan9, windows...
fmt.Printf("%s.\n", os)
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
func main() {
defer fmt.Println("2. world")
defer fmt.Println("1. ")
fmt.Println("0. hello")
}
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i) // print as 9\n 8\n ...., 0
}
fmt.Println("done")
}