最近又打算玩玩golang,打算把工作中的爬蟲從腳本語言遷移到golang,讀了兩本golang的書,對立面的語法做了一個簡單的整理。
編程語言的選擇
0 業務的要求1 性能2 表達能力3 是否容易上手4 坑和維護變量
變量的聲明var xx type 或者 var (xx type xxx type)初始化
var v1 i = 10; var v2 = 10; v3 := 10交換值
i,j = j,i多個值
_,a = 11,34常量
const pi float32 = 1.2const zero = 11const( a1 int32 = 11; a2 = 11;)const a2 = 1 << 2預定義常量
const( c0=iota;c1=iota;c2=iota;)//iota 值自動增加const (a = 1 << iota; b ; c;)枚舉
const( day1=iota;day2;day3;day4;)類型
bool var b1 bool = true; b2 := (1 == 2);int8,byte int16 int unit unitptr int32 unit32 int64 unit64 int unit 整型是不同的,數值運算,比較運算,位運算float32 float64 var f1 float32 = 11.1; 不能直接比較大小,可以計算減法比較complex64 complex128 com1 := 3+12i; 實部real(com1); 虛部imag(com1)string str1 := "hi"; len(str1);str1[0]; 字符串的運算 加 x+y 長度 len(s) 取字符 s[i] 字符串的遍歷 for k,v := range str{ fmt.PRintln(k,v); }rune字符類型 byte,uint8的別名,一個是rune 代表unicode字符 unicode/utf8包提供utf-8和unicode的轉換指針 pointer數組 array [32]int;[2*N]struct{x,y int32};[3][5]int 長度 alen := len(arr) 遍歷 下標遍歷,range遍歷, 數組是值類型,傳遞是拷貝切片 slice 創建切片 arr[a:b]; make([]int,len,cap); 遍歷 小標遍歷,range遍歷 常用函數 len長度 cap容量 可以基于切片創建切片 新增元素 slice=append(slice,11) 內容復制 copy(slice1,slice2);字典 map 創建字典 make(map[string]int,len) 賦值 map1[key] = val1 查找字典 p,ok := map1[key1] 刪除 delete(map1,"k1")通道 chan結構體 struct接口 interfaceerror流程語句
選擇 if,else 和else if if xxx{ }else{ } switch switch xx{ case 1: fallthrough case 2: default: } select循環 for for{} for a;b;c;{} break 跳出循環 continue 繼續 range 循環跳轉 HERE: goto HEREinit()函數main前調用
函數
func (t *R) funcname(a type,b type)(ret type, err error){ return a,nil}函數返回nil比較多調用 a:= funcname(a,b); a:= FTT.funcname(a,b); 不定參數 func funcname2(arg ...int){ funcname3(arg...) }任意參數 func funcname3(args ...interface{})匿名函數 func(x,y int)int{ return x+y } //調用匿名函數 func(x,y int)int{ print(x,y) }(1,2) 閉包: j :=3; func()(func()){ var i int = 1; return fun(){ fmt.Printf("i,j:%d,%d/n",i,j); } }()獲取數據的類型
xxx.(type)nil
代表空defer和panic 錯誤處理
error的定義type error interface{ Error() string}defer 延后處理 例如defer func(){}()panic() 和recover()
panic()釋放錯誤defer func(){ if r:= recover();r!=nil{ log.Printf("xxx"); }}()import
相對路徑 import "./xx"絕對路徑 import "xx/xx"點導入 import . "math" 可以直接 sqrt()別名 import f fmt 可以f.printf(xxx)_操作 _"github.com/xxx" 引用包不是直接調用函數,而是使用了包里面的init方法go的類型系統
基礎類型 byte int bool float符合類型 數組,結構體,指針任意類型 interface{}值和引用語義面向對象接口go 里面有引用語義的 切片,map,channel,接口結構
type A struct{ stat int}func ( a A) add(a1 int,b1 int ) int{ return a1+b1}初始化 a1 := new(A) a2 := &A{} a3 := &A{1} a4 := &A{stat:1}自建構造函數 func NewA(stat int){ return &A{stat} }匿名組合 type B struct{ A } type B struct{ *A }可見性 通過大小寫控制接口
type Read interface{ Reader(buf []byte)(n int,err error)}type FileReader struct{ int xx;}實現接口func (fr *FileReader)Reader(buf []byte)(n int,err error){ return 1,nil}接口的賦值 對象賦值給接口通過引用 file_reader := new(FileReader); var b Read = file_reader 將接口賦值給接口 只需要一個是另外一個的子集即可,反過來不成立 IA > IB IA = IB接口查詢 檢查是否實現了接口 if xx,ok := file_reader.(Read);ok{ }接口組合 type interface1 interface{ read()(n int,err error) } type interface2 interface{ write()(n int,err error) } type interface3 interface{ interface1 interface2 }任意類型
interface{}類型查詢
switch v:= v1.(type){ case xx1: case xx2: case xx3:}并發
通過go實現 main方法調用go的方式 1 主線程睡眠 2 使用管道等待 3 for或者select死循環管道的聲明 ch := make(chan int)管道寫入數據 ch <- value 管道數據寫入變量 value := <-chselect go在語言級別支持select select{ case <-chan1://chan1讀取數據執行下面 case chan2 <- 1: chan2讀取成功 default:默認流程 }緩沖機制-自帶線程池 c :=make(chan int,1023) for i:= range c{ printf("receiverd: ",i); }超時機制 1 定義一個chan運行,到時間寫即可,可以使用select來實現 2 也可以 使用 time.After(5.time.Second)傳遞性 可以通過chan傳遞數據 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) } }單向管道 讀寫 var ch1 chan int 寫 var ch2 chan<- float32 讀 var ch2 <-chan int關閉管道 close(ch)多核化 cpu個數的管道Gosched讓出時間片 同步 sync.Mutex sync.RWMutex 全局唯一操作 var once sync.Once once.Do(xxx)go并發相關函數: Goexit 退出去 Gosched 讓出執行權限 NumCPU cpu核數量 NumGoroutine 執行和排隊的攜程數 GOMAXPROCES 核心數反射
t := reflect.TypeOf(i) //得到類型的元數據,通過t我們能獲取類型定義里面的所有元素v := reflect.ValueOf(i) //得到實際的值,通過v我們獲取存儲在里面的值,還可以去改變值轉化為reflect對象之后我們就可以進行一些操作了,也就是將reflect對象轉化成相應的值,例如tag := t.Elem().Field(0).Tag //獲取定義在struct里面的標簽name := v.Elem().Field(0).String() //獲取存儲在第一個字段里面的值package mainimport ( _ "github.com/Go-SQL-Driver/MySQL" "database/sql" "fmt" //"time")func main() { db, err := sql.Open("mysql", "astaxie:astaxie@/test?charset=utf8") checkErr(err)//插入數據stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?") checkErr(err)res, err := stmt.Exec("astaxie", "研發部門", "2012-12-09") checkErr(err)}使用redis
package mainimport ( "github.com/astaxie/goredis" "fmt")func main() { var client goredis.Client client.Set("a", []byte("hello")) val, _ := client.Get("a") fmt.Println(string(val)) client.Del("a") //list操作 var client goredis.Client vals := []string{"a", "b", "c", "d", "e"} for _, v := range vals { client.Rpush("l", []byte(v)) } dbvals,_ := client.Lrange("l", 0, 4) for i, v := range dbvals { println(i,":",string(v)) } client.Del("l") }操作xml
package mainimport ( "encoding/xml" "fmt" "io/ioutil" "os")type Recurlyservers struct { XMLName xml.Name `xml:"servers"` Version string `xml:"version,attr"` Svs []server `xml:"server"` Description string `xml:",innerxml"`}type server struct { XMLName xml.Name `xml:"server"` ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"`}func main() { file, err := os.Open("servers.xml") // For read access. if err != nil { fmt.Printf("error: %v", err) return } defer file.Close() data, err := ioutil.ReadAll(file) if err != nil { fmt.Printf("error: %v", err) return } v := Recurlyservers{} err = xml.Unmarshal(data, &v) if err != nil { fmt.Printf("error: %v", err) return } fmt.Println(v) }正則表達式
func Match(pattern string, b []byte) (matched bool, error error)func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) func MatchString(pattern string, s string) (matched bool, error error)解析正則 func Compile(expr string) (*Regexp, error) func CompilePOSIX(expr string) (*Regexp, error) func MustCompile(str string) *Regexp func MustCompilePOSIX(str string) *Regexp查找 func (re *Regexp) Find(b []byte) []byte func (re *Regexp) FindAll(b []byte, n int) [][]byte func (re *Regexp) FindAllIndex(b []byte, n int) [][]int func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int func (re *Regexp) FindIndex(b []byte) (loc []int) func (re *Regexp) FindSubmatch(b []byte) [][]byte func (re *Regexp) FindSubmatchIndex(b []byte) []int目錄文件操作的大多數函數都是在os包里面,下面列舉了幾個目錄操作的: func Mkdir(name string, perm FileMode) error創建名稱為name的目錄,權限設置是perm,例如0777 func MkdirAll(path string, perm FileMode) error根據path創建多級子目錄,例如astaxie/test1/test2。 func Remove(name string) error刪除名稱為name的目錄,當目錄下有文件或者其他目錄是會出錯 func RemoveAll(path string) error根據path刪除多級子目錄,如果path是單個名稱,那么該目錄不刪除。文件 func Create(name string) (file *File, err Error) 根據提供的文件名創建新的文件,返回一個文件對象,默認權限是0666的文件,返回的文件對象是可讀寫 func NewFile(fd uintptr, name string) *File 根據文件描述符創建相應的文件,返回一個文件對象打開 func Open(name string) (file *File, err Error) 該方法打開一個名稱為name的文件,但是是只讀方式,內部實現其實調用了OpenFile。 func OpenFile(name string, flag int, perm uint32) (file *File, err Error) 名字,方式,權限寫func (file *File) Write(b []byte) (n int, err Error) 寫入byte類型的信息到文件func (file *File) WriteAt(b []byte, off int64) (n int, err Error) 在指定位置開始寫入byte類型的信息func (file *File) WriteString(s string) (ret int, err Error) 寫入string信息到文件讀 func (file *File) Read(b []byte) (n int, err Error) func (file *File) ReadAt(b []byte, off int64) (n int, err Error)字符串處理
字符串操作func Contains(s, substr string) boolfunc Join(a []string, sep string) stringfunc Index(s, sep string) intfunc Replace(s, old, new string, n int) stringfunc Repeat(s string, count int) stringfunc Split(s, sep string) []stringfunc Trim(s string, cutset string) stringfunc Fields(s string) []string字符串轉換 str := make([]byte, 0, 100) str = strconv.AppendInt(str, 4567, 10) str = strconv.AppendBool(str, false) str = strconv.AppendQuote(str, "abcdefg") str = strconv.AppendQuoteRune(str, '單') a := strconv.FormatBool(false) b := strconv.FormatFloat(123.23, 'g', 12, 64) c := strconv.FormatInt(1234, 10) d := strconv.FormatUint(12345, 10) e := strconv.Itoa(1023) a, err := strconv.ParseBool("false") if err != nil {fmt.Println(err) } b, err := strconv.ParseFloat("123.23", 64) if err != nil { fmt.Println(err) } c, err := strconv.ParseInt("1234", 10, 64) if err != nil { fmt.Println(err) } d, err := strconv.ParseUint("12345", 10, 64) if err != nil { fmt.Println(err) } e, err := strconv.Itoa("1023") if err != nil { fmt.Println(err) } fmt.Println(a, b, c, d, e) }websocket
"code.google.com/p/go.net/websocket" 服務gdb調試
日志系統
seelog部署
daemon性能監控
net/http/pprofruntime/pprof常用的庫
net包socket 庫 Dial(net,addr string)(Conn,error) conn,err := net.Dial("tcp","127.0.0.1:8888") conn,err := net.Dial("udp","127.0.0.1:8888") conn,err := net.Dial("ip4:icmp","www.baidu.com") conn,err := net.Dial("ip4:1","10.113.1.103") 目前支持的協議: tcp tcp4 tcp6 udp upd4 udp6 ip ip4 ip6dial實際上是對函數的封裝 func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error)func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)http庫,net/http包 func (c *Client) Get(url string) (r *Response, err error) func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error)func (c *Client) PostForm(url string, data url.Values) (r *Response, err error) func (c *Client) Head(url string) (r *Response, err error)func (c *Client) Do(req *Request) (resp *Response, err error)http服務端編程 http.Handle("/foo", fooHandler) http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) } ) log.Fatal(http.ListenAndServe(":8080", nil)) 或者是 s := &http.Server{ Addr:":8080", Handler:myHandler, ReadTimeout:10 * time.Second, ReadTimeout:10 * time.Second, MaxHeaderBytes: 1 << 20, } log.Fatal(s.ListenAndServe()) https有點不同 log.Fatal(http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)) RPC net/rpc直接支持 服務端 arith := new(Arith) rpc.Register(arith) rpc.HandleHTTP() l, e := net.Listen("tcp", ":1234") if e != nil { log.Fatal("listen error:", e) } go http.Serve(l, nil) 客戶端 client, err := rpc.DialHTTP("tcp", serverAddress + ":1234") if err != nil { log.Fatal("dialing:", err) } args := &server.Args{7,8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply) Gob Gob 是 Go 的一個序列化數據結構的編碼解碼工具 json處理 壓縮一個數據,放到另外一個數據里面 func Marshal(v interface{}) ([]byte, error) func Unmarshal(data []byte, v interface{}) error ?? JSON中的布??值將會??換為Go中的bool類型; ?? 數值會被??換為Go中的float64類型; 字符????換后還是string類型; JSON數組會??換為[]interface{}類型; JSON對象會??換為map[string]interface{}類型; ?? null值會??換為nil。 md5和sha1 package main import( "fmt" "crypto/sha1" "crypto/md5" ) Md5Inst:=md5.New() Md5Inst.Write([]byte(TestString)) Result:=Md5Inst.Sum([]byte("")) fmt.Printf("%x/n/n",Result) Sha1Inst:=sha1.New() Sha1Inst.Write([]byte(TestString)) Result=Sha1Inst.Sum([]byte("")) fmt.Printf("%x/n/n",Result)新聞熱點
疑難解答