顺序编程 变量 1 2 3 4 5 6 7 8 9 10 var v10 int v10 = 123 v11 := 234 // 匿名变量示例 func GetName() (firstName, lastName nickName string) {   return "May", "Chan", "Chibi" } _, _, nickName := GetName() 
 
常量 iota是一个特殊的常量,它会在每一个const关键字出现时重置为0,然后在下一个const出现前,每出现一次iota,它代表的值加1。如果两个const的赋值语句表达式一样,后一个赋值可省略。
1 2 3 4 5 const (   c0 = iota   c1 = iota   c2 ) 
 
枚举 1 2 3 4 5 6 7 8 9 10 const (   Sunday = iota   Monday   Tuesday   Wednesday   Thursday   Friday   Saturday   numberOfDays ) 
 
类型 
布尔:bool 
整型:int8、byte、int16、int、uint、unitptr等 
浮点:float32、float64 
复数:complex64、complex128 
字符串:string:在初始化后不能被修改 
字符:rune 
错误:error 
指针(pointer) 
数组(array) 
切片(slice):可动态增减元素 
字典(map) 
通道(chan) 
接口(interface) 
结构体(struct) 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 切片例子 mySlice := make([]int, 5, 10) fmt.Println("len(mySlice):", len(mySlice)) fmt.Println("cap(mySlice):", cap(mySlice)) mySlice = append(mySlice, 1, 2, 3) mySlice2 := []int{8, 9, 10} mySlice = append(mySlice, mySlice2) slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{5, 4, 3} copy(slice2, slice1) //将slice1中的前3个元素复制到slice2 copy(slice1, slice2) //将slice2中的前3个元素复制到slice1 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // Map例子 package main import ( 	"fmt" ) type PersonInfo struct{ 	ID string 	Name string 	Address string } func main(){ 	var personDB map[string] PersonInfo 	personDB = make(map[string] PersonInfo) 	personDB["12345"] = PersonInfo{"12345", "Tom", "Room 12345"} 	personDB["546"] = PersonInfo{"546", "Tom", "Room 546"} 	person, ok := personDB["1234"] 	if ok { 		fmt.Println("Found person", person.Name) 	}else{ 		fmt.Println("Did not find person") 	} 	delete(personDB, "546") 	fmt.Println(personDB["12345"].Name) } 
 
流程控制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 // if else func if_else(x int) int { 	if x == 0 { 		return 5 	}else{ 		return x 	} } // switch case func switch_case(i int){ //无需break 	switch i{ 	case 0: 		fmt.Println("0") 	case 1: 		fmt.Println("1") 	default: 		fmt.Println("Default") 	} } // for sum := 0 for { 	sum ++ 	if sum > 10 { 		break 	} } for j := 0; j < 5; j++ { 	ftm.Println(j) } // goto func myfunc(){ 	i := 0 	HERE: 	fmt.Println(i) 	i++ 	if i < 10 { 		goto HERE 	} } 
 
函数 1 2 import "mymath"  //假设Add被放在一个叫mymath的包中 c := mymath.Add(1, 2) 
 
小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。
1 2 3 4 5 6 7 8 9 10 11 12 func myfunc(args ...int) {   for _, arg := range args {     fmt.Println(arg) }  } func myfunc(args ...int) { 	for _, arg := range args { 		fmt.Println(arg) 	} 	myfunc2(args...) } 
 
任意类型的不定参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func Printf(format string, args ...interface{}){ 	for _, arg := range args { 		switch arg.(type) { 			case int: 				fmt.Println(arg, "is an int value") 			case string: 				fmt.Println(arg, "is a string value") 			case int64: 				fmt.Println(arg, "is an int64 value") 			default: 				fmt.Println(arg, "is an unknown type") 		} 	} } 
 
多返回值
1 func (file *File) Read(b []byte) (n int, err Error) 
 
匿名函数与闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package main import( 	"fmt" ) func main(){ 	var j int = 5 	a := func()(func()){ 		var i int = 10 		return func() { 			fmt.Printf("i, j: %d, %d\n", i, j) 		} 	}() 	a() 	j *= 2 	a() } // 结果 // i, j: 10, 5 // i, j: 10, 10 
 
异常处理 1 2 3 type error interface {   Error() string } 
 
大多数函数,如果要返回错误,可以定义如下模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func Foo(param int)(n int, err error) {   // ... } n, err := Foo(0) if err != nil {   // 错误处理 } else {   // 使用返回值n } type PathError struct {   Op string   Path string   Err  error } func (e *PathError) Error() string {   return e.Op + " " + e.Path + ": " + e.Err.Error() } 
 
defer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func CopyFile(dst, src string) (w int64, err error){ 	srcFile, err := os.Open(src) 	if err != nil { 		return 	} 	defer srcFile.Close() 	dstFile, err := os.Create(dst) 	if err != nil { 		return 	} 	defer dstFile.Close() 	return io.Copy(dstFile, srcFile) } 
 
panic/recover
1 2 3 4 5 defer func() { 	if r := recover(); r != nil { 		log.Printf("Runtime error caught: %v", r) 	} }() 
 
面向对象编程 结构体 1 2 3 4 type Integer int func (a Integer) Less(b Integer) bool {   return a < b } 
 
1 2 3 4 5 6 7 type Header map[string] []string func (h Header) Add(key, value string){   textproto.MIMEHeader(h).Add(key, value) } func (h Header) Set(key, value string){   textproto.MIMEHeader(h).Set(key, value) } 
 
引用类型:数组切片、map、channel、接口(interface) 值类型:byte、int、bool、float32、float64、string、array、struct、pointer等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 type Animal struct {     Name   string  //名称     Color  string  //颜色     Height float32 //身高     Weight float32 //体重     Age    int     //年龄 } //奔跑 func (a Animal)Run() {     fmt.Println(a.Name + "is running") } type Lion struct { 	Animal //匿名字段 } func main(){     var lion = Lion{         Animal{             Name:  "小狮子",             Color: "灰色",         },     }     lion.Run()     fmt.Println(lion.Name) } 
 
匿名组合相当于以其类型名称(去掉包名部分)作为成员变量的名字。 Go语言中,要使某个符号对其他包可见,需要将该符号定义为以大写字母开头。Go语言中符号的可访问性是包一级别,而不是类型级别。
接口 Go语言中,一个类只需要实现了接口要求的所有函数,就说这个类实现了该接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type File struct {   // ... } func (f *File) Read(buf []byte) (n int, err error) func (f *File) Write(buf []byte) (n int, err error) func (f *File) Close() error type IFile interface{   IReader   IWrite   IClose } type IReader interface{   Read(buf []byte) (n int, err error) } type IWriter interface{   Write(buf []byte) (n int, err error) } type IClose interface{   Close() error } var file1 IFile = new(File) var file2 IReader = new(File) 
 
Go语言中任何对象实例都满足空接口interface{}。
并发编程 go channel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package main import "fmt" func Count(ch chan int){ 	fmt.Println("Counting") 	ch <- 1 } func main(){ 	chs := make([]chan int, 10) 	for i :=0; i < 10; i++ { 		chs[i] = make(chan int) 		go Count(chs[i]) 	} 	for _, ch := range(chs) { 		a := <- ch 		fmt.Println(a) 	} } 
 
超时机制
1 2 3 4 5 6 7 8 9 10 11 12 timeout := make(chan bool, 1) go func(){ 	time.Sleep(1e9) 	timeout <- true }() select { case <-ch: 	//从ch中读取到数据 case <-timeout 	//一直没有从ch中读取到数据,但从timeout中读取到了数据 } 
 
channel的传递
1 2 3 4 5 6 7 8 9 10 11 12 type PipeData struct { 	value int 	handler func(int) int 	next chan int } func handle(queue chan *PipeData){ 	for data := range queue{ 		data.next <- data.handler(data.value) 	} } 
 
关闭channel
 
同步锁
1 2 3 4 5 6 var l sync.Mutex func foo(){ 	l.Lock() 	defer l.Unlock() 	//... } 
 
全局唯一操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var a string var once sync.once func setup(){ 	a = "hello" } func doprint() { 	once.Do(setup) 	print(a) } func twoprint(){ 	go doprint() 	go doprint() } 
 
以上代码setup只会运行一次。
网络编程 Socket编程 Dial():连接,支持如下协议:tcp,tcp4,tcp6,udp,udp4,udp6,ip,ip4,ip6
1 2 3 conn, err := net.Dial("tcp", "192.168.0.2:2100") conn2, err := net.Dial("udp", "192.168.0.2:53") conn3, err := net.Dial("ip4:icmp", "www.baidu.com") 
 
Write()与Read()方法来发送数据与接收数据。
HTTP编程 net/http包,包含HTTP客户端与服务端的具体实现。
1 2 3 4 5 6 resp, err := http.Get("http://example.com/") if err != nil{ 	return } defer resp.Body.close() io.Copy(os.Stdout, resp.Body) 
 
1 2 3 4 5 6 7 resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf) if err != nil{ 	return } if resp.StatusCode != http.StatusOK{ 	return } 
 
1 2 3 4 resp, err := http.PostForm("http://example.com/posts", url.Values{"title": {"article title"}, "content": {"artical body"}}) if err != nil{ 	return } 
 
1 resp, err := http.Head("http://example.com/") 
 
1 2 3 4 5 req, err := http.NewRequest("GET", "http://example.com/posts", nil) req.Header.Add("User-Agent", "Gobook User-Agent") client := &http.Client{...} resp, err := client.Do(req) 
 
1 2 3 http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request){   fmt.Fprintf(w, "hello") }) 
 
RPC net/rpc,包实现RPC协议的细节
1 func (t *T) MethodName(argType T1, replyType *T2) error 
 
T1与T2默认会使用encoding/gob包进行编码与解码。 argType表示由RPC客户端传入的参数 replyType表示要返回给RPC客户端的结果 服务端示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package main import ( 	"log" 	"net" 	"net/http" 	"net/rpc" ) type Args struct{ 	A, B int } type Arith int func (t *Arith) Multiply(args *Args, reply *int) error{ 	*reply = args.A * args.B 	return nil } func main(){ 	arith := new(Arith) 	rpc.Register(arith) 	rpc.HandleHTTP() 	l, e := net.Listen("tcp", ":1234") 	if e != nil{ 		log.Fatal("listen error", e) 	} 	http.Serve(l, nil) } 
 
客户端示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package main import ( 	"net/rpc" 	"fmt" 	"log" ) type Args struct{ 	A, B int } func main(){ // 顺序执行RPC 	client, _ := rpc.DialHTTP("tcp", "127.0.0.1:1234") 	args := &Args{7,8} 	var reply int 	err := client.Call("Arith.Multiply", args, &reply) 	if err != nil{ 		log.Fatal(err) 	} 	fmt.Println(reply) //异步执行RPC         var reply2 int 	divCall := client.Go("Arith.Multiply", &Args{6,8}, &reply2, nil) 	divCall = <-divCall.Done 	fmt.Println(reply2) } 
 
JSON encoding/json标准库 json.Marshal(),将一组数据进行JSON格式化编码 json.Unmarshal(),将JSON格式的文档解码为Go里边预期的数据结构。
1 2 3 4 5 6 7 8 data := make(map[string] string) data["name"] = "Michael" data2, err := json.Marshal(data) if err != nil{ 	fmt.Println("err") 	return } fmt.Println(string(data2[:])) 
 
1 2 3 4 5 data := make(map[string] string) data_json := []byte("{\"name\":\"Michael\"}") json.Unmarshal(data_json, &data) fmt.Println(data) 
 
反射 1 2 3 4 5 6 7 8 9 10 11 12 type T struct{ 	A int 	B string } t := T{203, "mh203"} s := reflect.ValueOf(&t).Elem() typeOfT := s.Type() for i := 0; i < s.NumField(); i++ { 	f := s.Field(i) 	fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) } 
 
Go工具 包文档查看(网站形式)
1 2 $ godoc -http=:8080 $ godoc -http=:8080 -path="." 
 
包文档查看(命令行形式)
 
代码格式化
1 2 $ go fmt hello.go $ gofmt -l -w . 
 
项目构建 go build:用于测试编译包,在项目目录下生成可执行文件(有main包);不能生成包文件 go install:主要用来生成库和工具。一是编译包文件(无main包),将编译后的包文件放到 pkg 目录下($GOPATH/pkg)。二是编译生成可执行文件(有main包),将可执行文件放到 bin 目录($GOPATH/bin);生成可执行文件在当前目录下, go install 生成可执行文件在bin目录下($GOPATH/bin)
1 2 $ GOOS=linux GOARCH=amd64 go build calc  $ go install calc 
 
GOOS:系统,linux/darwin/windows GOARCH:386/amd64
单元测试
 
模块管理go mod
1 2 3 $ go mod download  # 下载指定模块 $ go mod init test.com/go  #初始化当前模块 $ go mod vendor       # 将依赖复制到当前vendor目录下 
 
使用go module后,项目代码不需要放在GOPATH目录下。import项目的package时使用module路径。
以下是beego应用使用module来管理依赖的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ cat <<EOF > go.mod module beegoapp go 1.12 replace ( 	golang.org/x/crypto => github.com/golang/crypto v0.0.0-20191227163750-53104e6ec876 	golang.org/x/mod => github.com/golang/mod v0.1.0 	golang.org/x/net => github.com/golang/net v0.0.0-20191209160850-c0dbc17a3553 	golang.org/x/sync => github.com/golang/sync v0.0.0-20190911185100-cd5d95a43a6e 	golang.org/x/sys => github.com/golang/sys v0.0.0-20191228213918-04cbcbbfeed8 	golang.org/x/text => github.com/golang/text v0.3.2 	golang.org/x/tools => github.com/golang/tools v0.0.0-20191230220329-2aa90c603ae3 	golang.org/x/xerrors => github.com/golang/xerrors v0.0.0-20191204190536-9bdfabe68543 ) require ( 	github.com/astaxie/beego v1.12.0 	github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect 	github.com/smartystreets/goconvey v1.6.4 ) EOF