
順序編程
變量
var v10 int
v10 = 123
v11 := 234
// 匿名變量示例
func GetName() (firstName, lastName nickName string) {
return "May", "Chan", "Chibi"
}
_, _, nickName := GetName()
常量
iota是一個(gè)特殊的常量,它會(huì)在每一個(gè)const關(guān)鍵字出現(xiàn)時(shí)重置為0,然后在下一個(gè)const出現(xiàn)前,每出現(xiàn)一次iota,它代表的值加1。如果兩個(gè)const的賦值語句表達(dá)式一樣,后一個(gè)賦值可省略。
const (
c0 = iota
c1 = iota
c2
)
枚舉
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays
)
類型
- 布爾:bool
- 整型:int8、byte、int16、int、uint、unitptr等
- 浮點(diǎn):float32、float64
- 復(fù)數(shù):complex64、complex128
- 字符串:string:在初始化后不能被修改
- 字符:rune
- 錯(cuò)誤:error
- 指針(pointer)
- 數(shù)組(array)
- 切片(slice):可動(dòng)態(tài)增減元素
- 字典(map)
- 通道(chan)
- 接口(interface)
- 結(jié)構(gòu)體(struct)
// 切片例子
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個(gè)元素復(fù)制到slice2
copy(slice1, slice2) //將slice2中的前3個(gè)元素復(fù)制到slice1
// 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)
}
流程控制
// 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
}
}
函數(shù)
import "mymath" //假設(shè)Add被放在一個(gè)叫mymath的包中
c := mymath.Add(1, 2)
小寫字母開頭的函數(shù)只在本包內(nèi)可見,大寫字母開頭的函數(shù)才能被其他包使用。
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
myfunc2(args...)
}
任意類型的不定參數(shù)
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")
}
}
}
多返回值
func (file *File) Read(b []byte) (n int, err Error)
匿名函數(shù)與閉包
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()
}
// 結(jié)果
// i, j: 10, 5
// i, j: 10, 10
異常處理
type error interface {
Error() string
}
大多數(shù)函數(shù),如果要返回錯(cuò)誤,可以定義如下模式。
func Foo(param int)(n int, err error) {
// ...
}
n, err := Foo(0)
if err != nil {
// 錯(cuò)誤處理
} 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
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
defer func() {
if r := recover(); r != nil {
log.Printf("Runtime error caught: %v", r)
}
}()
面向?qū)ο缶幊?/h1>
結(jié)構(gòu)體
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
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)
}
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
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)
}
引用類型:數(shù)組切片、map、channel、接口(interface)
值類型:byte、int、bool、float32、float64、string、array、struct、pointer等
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)
}
匿名組合相當(dāng)于以其類型名稱(去掉包名部分)作為成員變量的名字。
Go語言中,要使某個(gè)符號(hào)對(duì)其他包可見,需要將該符號(hào)定義為以大寫字母開頭。Go語言中符號(hào)的可訪問性是包一級(jí)別,而不是類型級(jí)別。
接口
Go語言中,一個(gè)類只需要實(shí)現(xiàn)了接口要求的所有函數(shù),就說這個(gè)類實(shí)現(xiàn)了該接口。
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語言中任何對(duì)象實(shí)例都滿足空接口interface{}。
并發(fā)編程
go channel
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)
}
}
超時(shí)機(jī)制
timeout := make(chan bool, 1)
go func(){
time.Sleep(1e9)
timeout <- true
}()
select {
case <-ch:
//從ch中讀取到數(shù)據(jù)
case <-timeout
//一直沒有從ch中讀取到數(shù)據(jù),但從timeout中讀取到了數(shù)據(jù)
}
channel的傳遞
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)
}
}
關(guān)閉channel
close(ch)
同步鎖
var l sync.Mutex
func foo(){
l.Lock()
defer l.Unlock()
//...
}
全局唯一操作
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只會(huì)運(yùn)行一次。
網(wǎng)絡(luò)編程
Socket編程
Dial():連接,支持如下協(xié)議:tcp,tcp4,tcp6,udp,udp4,udp6,ip,ip4,ip6
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()方法來發(fā)送數(shù)據(jù)與接收數(shù)據(jù)。
HTTP編程
net/http包,包含HTTP客戶端與服務(wù)端的具體實(shí)現(xiàn)。
resp, err := http.Get("http://example.com/")
if err != nil{
return
}
defer resp.Body.close()
io.Copy(os.Stdout, resp.Body)
resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf)
if err != nil{
return
}
if resp.StatusCode != http.StatusOK{
return
}
resp, err := http.PostForm("http://example.com/posts", url.Values{"title": {"article title"}, "content": {"artical body"}})
if err != nil{
return
}
resp, err := http.Head("http://example.com/")
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)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "hello")
})
RPC
net/rpc,包實(shí)現(xiàn)RPC協(xié)議的細(xì)節(jié)
func (t *T) MethodName(argType T1, replyType *T2) error
T1與T2默認(rèn)會(huì)使用encoding/gob包進(jìn)行編碼與解碼。
argType表示由RPC客戶端傳入的參數(shù)
replyType表示要返回給RPC客戶端的結(jié)果
服務(wù)端示例
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)
}
客戶端示例
package main
import (
"net/rpc"
"fmt"
"log"
)
type Args struct{
A, B int
}
func main(){
// 順序執(zhí)行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)
//異步執(zhí)行RPC
var reply2 int
divCall := client.Go("Arith.Multiply", &Args{6,8}, &reply2, nil)
divCall = <-divCall.Done
fmt.Println(reply2)
}
JSON
encoding/json標(biāo)準(zhǔn)庫(kù)
json.Marshal(),將一組數(shù)據(jù)進(jìn)行JSON格式化編碼
json.Unmarshal(),將JSON格式的文檔解碼為Go里邊預(yù)期的數(shù)據(jù)結(jié)構(gòu)。
data := make(map[string] string)
data["name"] = "Michael"
data2, err := json.Marshal(data)
if err != nil{
fmt.Println("err")
return
}
fmt.Println(string(data2[:]))
data := make(map[string] string)
data_json := []byte("{\"name\":\"Michael\"}")
json.Unmarshal(data_json, &data)
fmt.Println(data)
反射
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工具
包文檔查看(網(wǎng)站形式)
$ godoc -http=:8080
$ godoc -http=:8080 -path="."
包文檔查看(命令行形式)
$ go doc foo
代碼格式化
$ go fmt hello.go
$ gofmt -l -w .
項(xiàng)目構(gòu)建
go build:用于測(cè)試編譯包,在項(xiàng)目目錄下生成可執(zhí)行文件(有main包);不能生成包文件
go install:主要用來生成庫(kù)和工具。一是編譯包文件(無main包),將編譯后的包文件放到 pkg 目錄下($GOPATH/pkg)。二是編譯生成可執(zhí)行文件(有main包),將可執(zhí)行文件放到 bin 目錄($GOPATH/bin);生成可執(zhí)行文件在當(dāng)前目錄下, go install 生成可執(zhí)行文件在bin目錄下($GOPATH/bin)
$ GOOS=linux GOARCH=amd64 go build calc
$ go install calc
GOOS:系統(tǒng),linux/darwin/windows
GOARCH:386/amd64
單元測(cè)試
$ go test calc
模塊管理go mod
$ go mod download # 下載指定模塊
$ go mod init test.com/go #初始化當(dāng)前模塊
$ go mod vendor # 將依賴復(fù)制到當(dāng)前vendor目錄下
使用go module后,項(xiàng)目代碼不需要放在GOPATH目錄下。import項(xiàng)目的package時(shí)使用module路徑。
以下是beego應(yīng)用使用module來管理依賴的例子
$ 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