// 当不知道json文件的格式时,可这样解析 b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`) var f interface{} err := json.Unmarshal(b, &f) if err == nil { m := f.(map[string]interface{}) for k, v := range m { switch vv := v.(type) { casestring: fmt.Println(k, "is string", vv) casefloat64: fmt.Println(k, "is float64", vv) case []interface{}: fmt.Println(k, "is an array:") for i, u := range vv { fmt.Println(i, u) } default: fmt.Println(k, "is of a type I don't know how to handle") } } }
// 对于流的Encoders和Decoders de := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) return } for k := range v { if k != "Name" { delete(v, k) } } if err := enc.Encode(&v); err != nil { log.Println(err) } }
Basic component
package | import
1 2 3 4 5 6 7 8 9 10 11 12
// 任何go程序都是由package组成,首个非空单词必须是package package main
// 单个import import"os"
// 多个import import ( "fmt" "math" )
functions
形式:形参的标识符在前,类型在后;返回值放在最后面
1 2 3 4
funcadd(x int, y int)int { return x + y }
这样做的主要原因是为了提高易读性,特别是在涉及函数变量(函数指针)的时候
1 2 3
f func(func(int,int)int, int) int f func(func(int,int)int, int) func(int, int)int
同类型的形参可简写
1 2 3 4
funcadd(x, y int)int { return x + y }
返回值可有多个
1 2 3 4 5 6 7 8 9
funcswap(x, y string) (string, string) { return y, x }
funcmain() { a, b := swap("hello", "world") fmt.Println(a, b) }
可给返回值命名,且return可简写,注意不要在长函数中简写,因为这样会降低可读性
1 2 3 4 5 6
funcsplit(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return }
variables | constants | types
首字母大写的变量称为exported name
1 2 3 4 5
type A struct { Address string// exported name cost int }
申明格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 单句 var c, python, java bool
// 有赋初值时,可省略类型名 var c, python, java = true, false, "no!" d := 3
// 创建一个位数为[dx][dy]的切片 a := make([][]uint8, dx) for i := range a { a[i] = make([]uint8, dy) }
第二种方式,不允许第二维大小有所变化,因为改变了就会有可能覆盖:
1 2 3 4 5 6 7 8 9
// Allocate the top-level slice, the same as before. picture := make([][]uint8, YSize) // One row per unit of y. // Allocate one large slice to hold all the pixels. pixels := make([]uint8, XSize*YSize) // Has type []uint8 even though picture is [][]uint8. // Loop over the rows, slicing each row from the front of the remaining pixels slice. for i := range picture { picture[i], pixels = pixels[:XSize], pixels[XSize:] }
可使用append函数向切片添加元素,假如切片容量不足,则容量会翻倍。
1 2 3 4 5 6
funcmain() { var s []int s = append(s, 2, 3, 4) fmt.Println(s) }
还可以使用append函数向切片中添加切片:
1 2 3 4 5
x := []int{1,2,3} y := []int{4,5,6} x = append(x, y...) fmt.Println(x)
funcadder()func(int)int { sum := 0 returnfunc(x int)int { sum += x return sum } }
funcmain() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } }
Flow control statements
if
if,可以没有(),但一定要有{}
1 2 3 4
if x < 0 { return sqrt(-x) + "i" }
if可以像for那样先带个statement。假如申明了变量,则只能在if或后续的else中使用。
1 2 3 4 5 6 7 8 9 10
funcpow(x, n, lim float64)float64 { if v := math.Pow(x, n); v < lim { return v } else { fmt.Printf("%g >= %g\n", v, lim) } // can't use v here, though return lim }
for
for,可以没有(),但一定要有{}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
for i := 0; i < 10; i++ { sum += i }
// 相当于while(condition) i := 0 for i < 10 { DoSomething(); i++; }
funcmain() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.\n", os) case"darwin": fmt.Println("OS X.") case"linux": fmt.Println("Linux.") } }
switch还可以这样写:
1 2 3 4 5 6 7 8 9 10 11 12
funcunhex(c byte)byte { switch { case'0' <= c && c <= '9': return c - '0' case'a' <= c && c <= 'f': return c - 'a' + 10 case'A' <= c && c <= 'F': return c - 'A' + 10 } return0 }
funcmain() { r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8) for { n, err := r.Read(b) fmt.Printf("n = %v err = %v b = %v\n", n, err, b) fmt.Printf("b[:n] = %q\n", b[:n]) if err == io.EOF { break } } }
Images 用于处理图像的接口
1 2 3 4 5 6
type Image interface { ColorModel() color.Model Bounds() Rectangle At(x, y int) color.Color }
Concurrency
Goroutines 轻型线程,它们共享同一地址的内存,需要同步控制
go f(x, y, z) 创建一个新Goroutine运行函数f
Channels 可用于传递数据的一种数据类型,需要用到运算符<-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
funcsum(s []int, c chanint) { sum := 0 for _, v := range s { sum += v } c <- sum // send sum to c }
funcmain() { s := []int{7, 2, 8, -9, 4, 0}
c := make(chanint) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c // receive from c
// 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] }
funcmain() { c := SafeCounter{v: make(map[string]int)} for i := 0; i < 1000; i++ { go c.Inc("somekey") }