go 笔记

字数 3894阅读 279

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来发送请求,进行更新和查询数据

推荐阅读更多精彩内容