go 筆記

fmt格式化字符串

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

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

變量

  1. python和go中變量的不同
    在go語言中當使用等號"="將一個變量的值賦值給另一個變量時,如:j = i,實際上是在內存中將i的值進行了拷貝,對于可變對象拷貝的是對象的地址。
    而python中沒有類型,類型屬于對象。使用等號"="將一個變量的值賦值給另一個變量時,如:j = i,i和j指向了相同的對象,當i重新賦值時,則i指向新的對象j不會發生改變.
    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. 多變量使用":="賦值時必須保證至少有一個變量是新的未聲明的變量

    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. 整數類型的最大值

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

goto語句

當goto語句在label之前時,在goto語句和label之間初始化變量會發生異常:

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改變函數的返回值

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

數組和切片

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

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

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

//數據的賦值發生內存拷貝
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重組,使切片的長度達到最大容量
        fmt.Printf("s1currentcaps=%d,lens=%d\n",cap(s1),len(s1))
    }
}
如果s2是一個 slice,你可以將 s2 向后移動一位 s2 = s2[1:],但是末尾沒有移動。切片只能向后移動,s2 = s2[-1:] 會導致編譯錯誤。切片不能被重新分片以獲取數組的前一個元素
切片為引用類型,使用make和new創建一個切片,以下兩種創建方式相同:
    make([]int, 10, 20)
    new([20]int)[0:10]

切片:

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

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

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

切片容量的收縮與擴容

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擴增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)擴增")
    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擴增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)擴增
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 是 引用類型 的: 內存用 make 方法來分配。

//map 的初始化
var map1[keytype]valuetype = make(map[keytype]valuetype)。
//或者簡寫為:map1 := make(map[keytype]valuetype)。
//判斷map類型key是否存在時可以使用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:當改字段的值為0值或未初始化時,則不現實該值
        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排序

    結構體類型,自定義多列排序

    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):斷言的動態類型x是一個具體類型T
    var w io.Writer
    w = os.Stdout
    f := w.(*os.File)      // success: f == os.Stdout
    
    1. x.(T):斷言的動態類型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轉換之后的值
    switch v:= x.(type) {
    case ....
    case ....
    }
    
  4. reflect 反射包

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

    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能否進行修改
            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))
            //函數使用: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數組或int數組等數組,不能直接賦值給空接口數組

    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. 結構體,集合,高級函數例子:

    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年之后出產的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. 當一個變量進行斷言判斷改變量是否實現某接口,則變量必須為接口類型,否則程序將panic

    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. 當切片類型做為接受者時,切片方法中需要改變切片的長度時,該參數必須為指針類型, 否則會無法成功修改該接受者

    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. 結構體零值,空指針的區別

    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' //控制結束字符
    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() // 不進行刷新buffer將不能寫入文件
    

json

  1. 使用"encoding/json"對struct進行序列化時字段名為小寫將不能被導出

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type Address struct {
        Country string
        Area    string
    }
    
    type Person struct {
        Name      string
        age       int //age字段不能被導出
        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) //將反序列化之后的數據存入變量p中
    
    json.Unmarshal([]byte(var),&p) //將反序列化之后的數據存入變量p中
    

channel

  1. golang中通道默認是阻塞的,如果通道處于等待狀態,程序無法處理時將發生deadlock

    對于同一個通道,發送操作(協程或者函數中的),在接收者準備好之前是阻塞的:如果ch中的數據無人接收,就無法再給通道傳入其他數據:新的輸入無法在通道非空的情況下傳入。所以發送操作會等待 ch 再次變為可用狀態:就是通道值被接收時(可以傳入變量)。

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

    
    //死鎖
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        ch := make(chan bool)
        //ch <- false //發生死鎖,程序運行該處時處于等待狀態,不能繼續運行 :fatal error: all goroutines are asleep - deadlock!
        go func() {
            fmt.Println(<-ch)
        }()
        ch <- false //放置該位置死鎖將不會發生,因為已啟動一個協程,等待ch通道放入數據
        time.Second(1e9) //1e9 == 1 * time.Second
    }
    
    
  2. 使用for循環通道需要顯示close channel不然會發生死鎖

    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. 生產者消費者模式

    /*
    生產者消費者模式
    */
    
    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

對包進行單元測試時,測試程序必須屬于被測試的包,并且文件名為*_test.go,該文件只在運行go test時進行編譯,測試函數名d的規范為TestFuncDesc, 已Test開頭,后面為測試的函數表述

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語句查詢中的字段的別名相關,如“SumAddUser”語句中的別名必須為sum_add_user, 結構體中的字段名的在"sql語句中"大寫字母前需要加下劃線(首字母除外),全部轉換為小寫

os模塊

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

數據競爭

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

  1. 避免多個gorouting訪問數據,使數據的讀寫都在一個gorouting,其他gorouting不能直接訪問變量,必須使用channel來發送請求,進行更新和查詢數據
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容