go 筆記

fmt格式化字符串

格式:%[旗標(biāo)][寬度][.精度][arg索引]動詞
旗標(biāo)有以下幾種:
+: 對于數(shù)值類型總是輸出正負(fù)號;對于%q(%+q)保證只輸出ASCII編碼的字符
-: 在右邊進(jìn)行寬度填充,而不是默認(rèn)的左邊
空格: 對于數(shù)值類型的正數(shù),保留一個(gè)空白的符號位
0: 用"0"進(jìn)行寬度填充而不用空格,對于數(shù)值類型,符號將被移到所有0的前面
#: 備用格式:為八進(jìn)制添加前綴0(%#o);為十六進(jìn)制添加前綴0x(%#x)或者0X(%#X);為%p(%#p)去掉前綴0x;
(其中 "0" 和 "-" 不能同時(shí)使用,優(yōu)先使用 "-" 而忽略 "0")

fmt.Printf("%010.2[2]s","abc","edf") //00000000ed
fmt.Printf("%010.4[1]s","abcd","edf") //000000abcd

變量

  1. python和go中變量的不同
    在go語言中當(dāng)使用等號"="將一個(gè)變量的值賦值給另一個(gè)變量時(shí),如:j = i,實(shí)際上是在內(nèi)存中將i的值進(jìn)行了拷貝,對于可變對象拷貝的是對象的地址。
    而python中沒有類型,類型屬于對象。使用等號"="將一個(gè)變量的值賦值給另一個(gè)變量時(shí),如:j = i,i和j指向了相同的對象,當(dāng)i重新賦值時(shí),則i指向新的對象j不會發(fā)生改變.
    python:

    >>> a=30
    >>> b=30
    >>> id(a)
    139846183992768
    >>> id(b)
    139846183992768
    >>> c=a
    >>> id(c)
    139846183992768
    

    golang

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        a := 10
        b := 10
        c := a
        fmt.Printf("a address: %p\n",&a)
        fmt.Printf("b address: %p\n",&b)
        fmt.Printf("c address: %p\n",&c)
    }
    /*
    output:
    a address: 0x1040e0f8
    b address: 0x1040e0fc
    c address: 0x1040e130
    */
    
  2. 多變量使用":="賦值時(shí)必須保證至少有一個(gè)變量是新的未聲明的變量

    var err error
    fn, err := os.Open("demo.go")
    defer fn.Close()
    if err != nil {
        panic(err)
    }
    /*fn, err := os.Open("demo.go") // no new variables on left side of :=
    defer fn.Close()
    if err != nil {
        panic(err)
    }
    */
    fn1, err := os.Open("demo.go")
    defer fn1.Close()
    if err != nil {
        panic(err)
    }
    
    
  3. go語言中任何類型的變量都會存在零值

    func Test_vrrar(t *testing.T) {
        var i int
        var s string
        var st struct {
            name string
        }
        var sarr []string
        var marr map[string]int
        fmt.Printf("string:'%s'\n", s)
        fmt.Printf("int:'%d'\n", i)
        fmt.Printf("struct:'%#v'\n", st)
        fmt.Printf("slice:'%#v'\n", sarr)
        fmt.Printf("map:'%#v'\n", marr)
        //相同字符輸出N次
        fmt.Println(strings.Repeat("x",10))
        if sarr != nil {
            panic("ok")
        }
        if marr != nil {
            panic("ok")
        }
    }
    /*output
    === RUN   Test_vrrar
    string:''
    int:'0'
    struct:'struct { name string }{name:""}'
    slice:'[]string(nil)'
    map:'map[string]int(nil)'
    --- PASS: Test_vrrar (0.00s)
    PASS
    ok      base/variable/test  0.068s
    */
    
  4. 整數(shù)類型的最大值

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        var a uint32
        a = 1
        fmt.Println(a<<32-1) #1向左移動最大值即為最大值
    }
    

goto語句

當(dāng)goto語句在label之前時(shí),在goto語句和label之間初始化變量會發(fā)生異常:

package main
import "fmt"
func main() {                  
        goto ABC               
        b := 20 //goto ABC jumps over declaration of b at demo5/t.go:8 
        fmt.Printf("test goto b=%d\n", b)
ABC:
        fmt.Println("goto over")        
}

defer

使用defer改變函數(shù)的返回值

func main() {
    var i  = f() 
    fmt.Println(i)  // ouput: 2
}
func f() (ret int) {
    defer func(){
        ret = 2 
    }() 
    return 0
}

數(shù)組和切片

go語言中基本類型都為值類型 , 且數(shù)組也為值類型, 切片是引用類型
slice長度可變是指可以通過"重新切片" 來達(dá)到容量上線,(append也可以實(shí)現(xiàn)擴(kuò)容, 但當(dāng)切片容量超過原有的容量時(shí),切片空間擴(kuò)充一倍)

var s1=make([]string,0,10)
var arr1=[9]string{"a","b","c","d","e","f","g"} 
s1 = arr1[:]
fmt.Printf("len(s1)=%d,cap(s1)=%d\n",len(s1),cap(s1))
//len(s1)=9,cap(s1)=9

//打印內(nèi)存地址
fmt.Printf("%p\n",s1)

//數(shù)據(jù)的賦值發(fā)生內(nèi)存拷貝
var a1 [3]int = [3]int{1, 3, 4}
a2 := a1
fmt.Printf("a1:%p\n", &a1) // a1:0xc042010360
fmt.Printf("a2:%p\n", &a2) //a2:0xc042010380


切片重組:

funcslice_merge(){
    s1:=make([]int,0,20)
    for i:=0;i<cap(s1);i++{
        s1=s1[0:len(s1)+1]//通過使用slice重組,使切片的長度達(dá)到最大容量
        fmt.Printf("s1currentcaps=%d,lens=%d\n",cap(s1),len(s1))
    }
}
如果s2是一個(gè) slice,你可以將 s2 向后移動一位 s2 = s2[1:],但是末尾沒有移動。切片只能向后移動,s2 = s2[-1:] 會導(dǎo)致編譯錯誤。切片不能被重新分片以獲取數(shù)組的前一個(gè)元素
切片為引用類型,使用make和new創(chuàng)建一個(gè)切片,以下兩種創(chuàng)建方式相同:
    make([]int, 10, 20)
    new([20]int)[0:10]

切片:

如果想增加切片的容量,我們必須創(chuàng)建一個(gè)新的更大的切片并把原分片的內(nèi)容都拷貝過來。
下面的代碼描述了從拷貝切片的 copy 函數(shù)和向切片追加新元素的 append 函數(shù)。
當(dāng)在函數(shù)中更改參數(shù)切片的元素時(shí),會更改該參數(shù) 變量的值:可以使用copy方法:

s :=[]int{2,3,4,5,6,7}
s1 := make([]int, len(s))
copy(s1,s)

//go 中函數(shù)調(diào)用的省略號:
functest6(){
    vara=make([]byte,20)
    copy(a[12:],"ccccc")
    fmt.Println(a)
    a=append(a,"ffff"...) //使用了省略號(…)來自動展開切片
    fmt.Println(a)
}

切片容量的收縮與擴(kuò)容

package main

import (
    "log"
)

func main() {
    var s = []int{1, 2, 3, 4, 5, 6, 7}
    log.Printf("len(s)=%d,cap(s)=%d\n", len(s), cap(s))
    log.Println("使用append擴(kuò)增slice(s)容量")
    s = append(s, 8)
    log.Printf("len(s)=%d,cap(s)=%d\n", len(s), cap(s))
    log.Printf("slice(s)=%v\n", s)
    log.Printf("slice(s) ")
    s = s[:5]
    log.Printf("len(s)=%d,cap(s)=%d\n", len(s), cap(s))
    log.Printf("slice(s)=%v\n", s)
    log.Printf("slice(s)擴(kuò)增")
    s = s[:12]
    log.Printf("len(s)=%d,cap(s)=%d\n", len(s), cap(s))
    log.Printf("slice(s)=%v\n", s)
}
/*OUTPUT
2016/06/27 16:25:17 len(s)=7,cap(s)=7
2016/06/27 16:25:17 使用append擴(kuò)增slice(s)容量
2016/06/27 16:25:17 len(s)=8,cap(s)=14
2016/06/27 16:25:17 slice(s)=[1 2 3 4 5 6 7 8]
2016/06/27 16:25:17 slice(s)收縮
2016/06/27 16:25:17 len(s)=5,cap(s)=14
2016/06/27 16:25:17 slice(s)=[1 2 3 4 5]
2016/06/27 16:25:17 slice(s)擴(kuò)增
2016/06/27 16:25:17 len(s)=12,cap(s)=14
2016/06/27 16:25:17 slice(s)=[1 2 3 4 5 6 7 8 0 0 0 0]
*/

使用bufio的Scanner讀取文本:

package main

import (
    "bufio"
    "log"
    "strings"
)

/*
使用bufio的Scanner讀取文本
*/
func main() {
    input := strings.NewReader("小名 and 小明 and 小名 and 小米 and 小華 is different ")
    wMap := make(map[string]int)
    scanner := bufio.NewScanner(input)
    scanner.Split(bufio.ScanWords)
    for scanner.Scan() {
        wMap[scanner.Text()]++
    }
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
    log.Println(wMap)
}

MAP

map 是 引用類型 的: 內(nèi)存用 make 方法來分配。

//map 的初始化
var map1[keytype]valuetype = make(map[keytype]valuetype)。
//或者簡寫為:map1 := make(map[keytype]valuetype)。
//判斷map類型key是否存在時(shí)可以使用isPresent 形式:
var d1=map[int]string{1:"abc",2:"eeeee"}
if  val,ok:=d1[1];ok{
    fmt.Print(val)
}

序列化

  1. json序列化與反序列化
    package main
    
    import (
        "encoding/json"
        "log"
    )
    
    type Person struct {
        //omitempty:當(dāng)改字段的值為0值或未初始化時(shí),則不現(xiàn)實(shí)該值
        Name string `json:"name,omitempty"`
        Age  int    `json:"age,omitempty"`
    }
    
    func main() {
        var p = []Person{Person{Name: "kanghw", Age: 12}, Person{}, Person{Name: "pp"}, Person{Age: 10}}
        out, _ := json.MarshalIndent(p, "", "    ")
        log.Printf("\n%s\n", string(out))
    
        var ps []Person
        //反序列化
        if err := json.Unmarshal(out, &ps); err != nil {
            log.Fatal(err)
        }
        log.Printf("%#v\n", ps)
    }
    

interface:

  1. sort排序

    結(jié)構(gòu)體類型,自定義多列排序

    package main
    
    import (
        "fmt"
        "os"
        "sort"
        "text/tabwriter"
        "time"
    )
    
    type Track struct {
        Title  string
        Artist string
        Album  string
        Year   int
        Length time.Duration
    }
    
    var tracks = []*Track{
        {"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
        {"Go", "Moby", "Moby", 1992, length("3m37s")},
        {"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
        {"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
    }
    
    func length(s string) time.Duration {
        d, err := time.ParseDuration(s)
        if err != nil {
            panic(s)
        }
        return d
    }
    
    func printTracks(tracks []*Track) {
        const format = "%v\t%v\t%v\t%v\t%v\t\n"
        tw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)
        fmt.Fprintf(tw, format, "Title", "Artist", "Album", "Year", "Length")
        fmt.Fprintf(tw, format, "-----", "------", "-----", "----", "------")
        for _, t := range tracks {
            fmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)
        }
        tw.Flush() // calculate column widths and print table
    }
    
    type customSort struct {
        t    []*Track
        less func(x, y *Track) bool
    }
    
    func (x customSort) Len() int           { return len(x.t) }
    func (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }
    func (x customSort) Swap(i, j int)      { x.t[i], x.t[j] = x.t[j], x.t[i] }
    
    func main() {
        printTracks(tracks)
        sort.Sort(customSort{tracks, func(x, y *Track) bool {
            if x.Title != y.Title {
                return x.Title < y.Title
            }
            if x.Year != y.Year {
                return x.Year < y.Year
            }
            if x.Length != y.Length {
                return x.Length < y.Length
            }
            return false
        }})
        fmt.Println("sorted:")
    
        printTracks(tracks)
    }
    /*output:
    Title       Artist          Album              Year  Length  
    -----       ------          -----              ----  ------  
    Go          Delilah         From the Roots Up  2012  3m38s   
    Go          Moby            Moby               1992  3m37s   
    Go Ahead    Alicia Keys     As I Am            2007  4m36s   
    Ready 2 Go  Martin Solveig  Smash              2011  4m24s   
    sorted:
    Title       Artist          Album              Year  Length  
    -----       ------          -----              ----  ------  
    Go          Moby            Moby               1992  3m37s   
    Go          Delilah         From the Roots Up  2012  3m38s   
    Go Ahead    Alicia Keys     As I Am            2007  4m36s   
    Ready 2 Go  Martin Solveig  Smash              2011  4m24s  
    */
    
  2. 類型斷言

    1. x.(T):斷言的動態(tài)類型x是一個(gè)具體類型T
    var w io.Writer
    w = os.Stdout
    f := w.(*os.File)      // success: f == os.Stdout
    
    1. x.(T):斷言的動態(tài)類型x是否滿足接口類型T
    var w io.Writer
    w = os.Stdout
    rw := w.(io.ReadWriter) // success: *os.File has both Read and Write
    
  3. switch類型斷言

    v:= x.(type) //v的值為x轉(zhuǎn)換之后的值
    switch v:= x.(type) {
    case ....
    case ....
    }
    
  4. reflect 反射包

    如果在反射中修改值,需要在reflect.ValueOf()傳遞指針參數(shù),才能達(dá)到修改源數(shù)據(jù)的目的,并使用Elem() 函數(shù)
    在結(jié)構(gòu)體中只有名稱首字母大寫的字段才是可設(shè)置的

    package main
    import (
    "fmt"
    "reflect"
    )
    type Person struct {
        Name string
        age  int
    }
    func (this Person) GName() string {
        return this.Name
    }
        
    func (this *Person) Setage(age int) {
        this.age = age
    }
            
    func main() {
        p := Person{"pp", 12}
        v := reflect.ValueOf(&p).Elem()
        typeofp1 := v.Type()
        for i := 0; i < reflect.TypeOf(p).NumField(); i++ {
            fmt.Printf("Field %v:%v\n", typeofp1.Field(i).Name, v.Field(i))
            //使用CanSet()判斷object能否進(jìn)行修改
            fmt.Println(v.Field(i).CanSet())
        }
        v.Field(0).SetString("kanghw")
        //panic: reflect: reflect.Value.SetInt using value obtained using unexported field
        //v.Field(1).SetInt(22)
        fmt.Println(p)
        for i := 0; i < reflect.ValueOf(p).NumMethod(); i++ {
            fmt.Printf("Method %d:%v\n", i, v.Method(i))
            //函數(shù)使用:Method(n).Call(nil)
            fmt.Println(v.Method(i).Call(nil))
        }
    }
    /*output:
        Field Name:pp
        true
        Field age:12  
        false  
        {kanghw 12}  
        Method 0:0x487570  
        [kanghw]
    */
    
  5. string數(shù)組或int數(shù)組等數(shù)組,不能直接賦值給空接口數(shù)組

    package main
    type obj interface{}
    
    func main() {
        s := []string{"aa", "bb", "cc"}
        arr_o := make([]obj, len(s))
        /*arr_o = s
        cannot use s (type []string) as type []obj in assignment
        */
        for index, val := range s {
            arr_o[index] = val
        }
    }
    
  6. 結(jié)構(gòu)體,集合,高級函數(shù)例子:

    package main
    
    import (
        "fmt"
    )
    
    type Any interface{}
    
    type Car struct {
        Model        string
        Manufacturer string
        BuildYear    int
    }
    
    type Cars []*Car
    
    //Process
    func (cs Cars) Process(f func(car *Car)) {
        for _, c := range cs {
            f(c)
        }
    }
    
    //FindAll
    
    func (cs Cars) FindAll(f func(car *Car) bool) Cars {
        cars := make([]*Car, 0)
        cs.Process(func(c *Car) {
            if f(c) {
                cars = append(cars, c)
            }
        })
        return cars
    }
    
    //Map
    
    func (cs Cars) Map(f func(car *Car) Any) []Any {
        res := make([]Any, 0)
        cs.Process(func(c *Car) {
            res = append(res, f(c))
        })
        return res
    }
    
    func MakeSortedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {
        sortedCars := make(map[string]Cars)
        for _, m := range manufacturers {
            sortedCars[m] = make([]*Car, 0)
        }
    
        sortedCars["Default"] = make([]*Car, 0)
        appender := func(c *Car) {
            if _, ok := sortedCars[c.Manufacturer]; ok {
                sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)
            } else {
                sortedCars["Default"] = append(sortedCars["Default"], c)
            }
        }
        return appender, sortedCars
    }
    
    func main() {
        ford := &Car{"Fiesta", "Ford", 2008}
        bmw := &Car{"XL 450", "BMW", 2001}
        merc := &Car{"D600", "Mercedes", 2009}
        benchu := &Car{"X750", "BEMCHI", 2011}
        allCars := Cars([]*Car{ford, bmw, merc, benchu})
        //所有2000年之后出產(chǎn)的BMW汽車
        allNewBMWs := allCars.FindAll(func(c *Car) bool {
            return (c.Manufacturer == "BMW") && (c.BuildYear > 2000)
        })
        fmt.Println("All Cars:", allCars)
        fmt.Println("New BMW:", allNewBMWs)
        //
        manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jagur"}
        sortedAppender, sortedCars := MakeSortedAppender(manufacturers)
        allCars.Process(sortedAppender)
        fmt.Println("Map sortedCars: ", sortedCars)
        BMWCount := len(sortedCars["BMW"])
        fmt.Println("We have ", BMWCount, " BMWS")
    }
    
    
  7. 當(dāng)一個(gè)變量進(jìn)行斷言判斷改變量是否實(shí)現(xiàn)某接口,則變量必須為接口類型,否則程序?qū)anic

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    type Per interface {
        String()
    }
    
    type Person struct {
        Name string
        Age  int
    }
    
    func (this Person) String() {
        fmt.Println(this.Name + strconv.Itoa(this.Age))
    }
    
    func main() {
        p := Person{"kang", 13}
        /*
            if p, ok := p.(Per); ok {
                fmt.Println(p)
            }
        */
        //invalid type assertion: p.(Per) (non-interface type Person on left)
        var obj interface{}
        obj = p
        if obj, ok := obj.(Per); ok {
            fmt.Println(obj)
        }
    }
    
    
  8. 當(dāng)切片類型做為接受者時(shí),切片方法中需要改變切片的長度時(shí),該參數(shù)必須為指針類型, 否則會無法成功修改該接受者

    package main
    
    import (
        "fmt"
    )
    
    type obj interface{}
    
    type stacker interface {
        push(obj)
        pop() obj
        Len() int
    }
    
    type stack []obj
    
    func (this stack) Len() int {
        return len(this)
    }
    
    func (this *stack) pop() obj { //this 必須為指針類型
        stk := *this
        if stk.Len() == 0 {
            panic("stack is empty")
        }
        res := stk[stk.Len()-1]
        *this = stk[0 : stk.Len()-1]
        return res
    }
    
    func (this *stack) push(em obj) {
        stk := *this
        *this = append(stk, em)
    }
    
    func main() {
        test := stack([]obj{"a", "b", "d"})
        fmt.Println(test.pop())
        test.push("sdfsdf")
        fmt.Println(test)
    }
    
  9. 結(jié)構(gòu)體零值,空指針的區(qū)別

    type Person struct {
        name string
        age  int 
    }
    
    func main() {
        var p1 *Person //(*main.Person)(nil) 
        var p2 Person  //main.Person{name:"", age:0}
        var p3 = new(Person) //*main.Person{name:"", age:0}
        //p1為空指針
    

讀取用戶輸入

  1. 使用fmt包的Scan和Sscan讀取輸入

    var firstName, lastName, s string
    var f float32 
    var i int
    input := "12.1:20:aaa"
    format := "%f:%d:%s"
    fmt.Println("please enter your name:")
    fmt.Scanln(&firstName, &lastName) //必須使用&符號
    fmt.Sscanf(input, format, &f, &i, &s)
    
  2. 使用bufio包提供的緩沖讀取

    endstr := '\n' //控制結(jié)束字符
    var reader *bufio.Reader
    var format = "%s %s %d"
    var name, sex string
    var age int
    reader = bufio.NewReader(os.Stdin)
    fmt.Printf("please your name sex age, format is %s:\n", format)
    
    output, err := reader.ReadString(endstr)
    

讀取文件

  1. 使用bufio包讀取

    fn, err := os.Open(filename)    
    reader := bufio.NewReader(fn)
    //line, _, err := reader.ReadLine()
    line, err := reder.ReadString('\n')
            
    
  2. 使用切片讀取

    buf := make([]byte, 1024)
    n, err := fn.Read(buf)
    
  3. 使用io/ioutil包讀取

    buf, err := ioutil.ReadFile(filename)
    
  4. 寫入文件

    fn ,_ := os.OpenFile(filename, os.O_APPEND|os.O_CREATE,0644)
    var wirter = bufio.NewWriter(fn)
    n, _ := writer.WriteString(str)
    writer.Flush() // 不進(jìn)行刷新buffer將不能寫入文件
    

json

  1. 使用"encoding/json"對struct進(jìn)行序列化時(shí)字段名為小寫將不能被導(dǎo)出

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type Address struct {
        Country string
        Area    string
    }
    
    type Person struct {
        Name      string
        age       int //age字段不能被導(dǎo)出
        Addresses []*Address
    }
    
    func main() {
        add1 := &Address{"中國", "河南"}
        add2 := &Address{"中國", "北京"}
        add3 := &Address{"澳洲", "悉尼"}
        p := Person{"pp", 23, []*Address{add1, add2, add3}}
        //fmt.Printf("%#v\n", p)
        var vals []byte
        var err error
        //vals, err = json.Marshal(p)//無格式化的輸出
        vals, err = json.MarshalIndent(p, "", "    ")
        if err != nil {
            panic(err)
        } else {
            fmt.Printf("%s\n", vals)
        }
    }
    
    /*output:
    {
        "Name": "康海偉",
        "Addresses": [
            {
                "Country": "中國",
                "Area": "河南"
            },
            {
                "Country": "中國",
                "Area": "北京"
            },
            {
                "Country": "澳洲",
                "Area": "悉尼"
            }
        ]
    }
    */
    
  2. json寫入文件,及反序列化

    fn, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0666)
    wrio := json.NewEncoder(fn)
    wrio.Encode(any) //寫入文件
    erio := json.NewDecoder(fn)
    erio.Decode(&p) //將反序列化之后的數(shù)據(jù)存入變量p中
    
    json.Unmarshal([]byte(var),&p) //將反序列化之后的數(shù)據(jù)存入變量p中
    

channel

  1. golang中通道默認(rèn)是阻塞的,如果通道處于等待狀態(tài),程序無法處理時(shí)將發(fā)生deadlock

    對于同一個(gè)通道,發(fā)送操作(協(xié)程或者函數(shù)中的),在接收者準(zhǔn)備好之前是阻塞的:如果ch中的數(shù)據(jù)無人接收,就無法再給通道傳入其他數(shù)據(jù):新的輸入無法在通道非空的情況下傳入。所以發(fā)送操作會等待 ch 再次變?yōu)榭捎脿顟B(tài):就是通道值被接收時(shí)(可以傳入變量)。

    對于同一個(gè)通道,接收操作是阻塞的(協(xié)程或函數(shù)中的),直到發(fā)送者可用:如果通道中沒有數(shù)據(jù),接收者就阻塞了。

    
    //死鎖
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        ch := make(chan bool)
        //ch <- false //發(fā)生死鎖,程序運(yùn)行該處時(shí)處于等待狀態(tài),不能繼續(xù)運(yùn)行 :fatal error: all goroutines are asleep - deadlock!
        go func() {
            fmt.Println(<-ch)
        }()
        ch <- false //放置該位置死鎖將不會發(fā)生,因?yàn)橐褑右粋€(gè)協(xié)程,等待ch通道放入數(shù)據(jù)
        time.Second(1e9) //1e9 == 1 * time.Second
    }
    
    
  2. 使用for循環(huán)通道需要顯示close channel不然會發(fā)生死鎖

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        ch := make(chan string)
        go func() {
            ch <- "sdfsfdsf"
            ch <- "sdfsfdsf"
            close(ch) //如果沒有close:fatal error: all goroutines are asleep - deadlock!
        }()
        for c := range ch {
            fmt.Println(c)
        }
    }
    
  1. 生產(chǎn)者消費(fèi)者模式

    /*
    生產(chǎn)者消費(fèi)者模式
    */
    
    func product(n int) chan int {
        ch := make(chan int)
        go func() {
            for i := 0; i < n; i++ {
                ch <- i
            }
        }()
        return ch
    }
    
    func consumer(n int, ch chan int) {
        go func() {
            for i := 0; i < n; i++ {
                fmt.Println(<-ch)
            }
        }()
    }
    
    func main() {
        runtime.GOMAXPROCS(runtime.NumCPU()) 
        var n = 10000
        consumer(n, product(n))
        time.Sleep(5 * time.Second)
    }
    

測試test

對包進(jìn)行單元測試時(shí),測試程序必須屬于被測試的包,并且文件名為*_test.go,該文件只在運(yùn)行g(shù)o test時(shí)進(jìn)行編譯,測試函數(shù)名d的規(guī)范為TestFuncDesc, 已Test開頭,后面為測試的函數(shù)表述

xorm序列化module

type resUseroverview struct {
    Cdate              string `json:"d"`
    SumAddUser         int64  `json:"SumAU"`
    SumAddUserPhone    int64  `json:"SumAUP"`
    SumAddUserDeviceid int64  `json:"SumAUD"`
    SumUserAct         int64  `json:"SumUA"`
    SumMvalueCount     int64  `json:"SumMC"`
    SumMvalueMva       int64  `json:"SumMM"`
    SumActCount        int64  `json:"SumAC"`
    SumActMva          int64  `json:"SumAM"`
}
//json為:序列化json中key的值
//而字段為名"SumAddUser" 與sql語句查詢中的字段的別名相關(guān),如“SumAddUser”語句中的別名必須為sum_add_user, 結(jié)構(gòu)體中的字段名的在"sql語句中"大寫字母前需要加下劃線(首字母除外),全部轉(zhuǎn)換為小寫

os模塊

使用os模塊創(chuàng)建文件,打開標(biāo)記:
O_RDONLY:只讀模式(read-only)
O_WRONLY:只寫模式(write-only)
O_RDWR:讀寫模式(read-write)
O_APPEND:追加模式(append)
O_CREATE:文件不存在就創(chuàng)建(create a new file if none exists.)
O_EXCL:與 O_CREATE 一起用,構(gòu)成一個(gè)新建文件的功能,它要求文件必須不存在(used with O_CREATE, file must not exist)
O_SYNC:同步方式打開,即不使用緩存,直接寫入硬盤
O_TRUNC:打開并清空文件

數(shù)據(jù)競爭

只要不同的gorouting訪問同一個(gè)變量,且一個(gè)存在更改操作,就存在數(shù)據(jù)競爭, 避免數(shù)據(jù)的方法:

  1. 避免多個(gè)gorouting訪問數(shù)據(jù),使數(shù)據(jù)的讀寫都在一個(gè)gorouting,其他gorouting不能直接訪問變量,必須使用channel來發(fā)送請求,進(jìn)行更新和查詢數(shù)據(jù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容