zoukankan      html  css  js  c++  java
  • Go基础

    Go 环境安装:

    Go 的安装配置(go 1.14):

    参看博客: 

    https://www.liwenzhou.com/posts/Go/go_menu/  

    https://www.liwenzhou.com/posts/Go/00_go_in_vscode/

    https://blog.csdn.net/AdolphKevin/article/details/105480530 

    https://studygolang.com/pkgdoc

    下载地址: https://golang.google.cn/dl/  

    安装好之后,配置GOPATH ,

    下载 vs code 编辑器,

    先在cmd 中: 

    go env -w GO111MODULE=on 

    go env -w GOPROXY=https://goproxy.cn,direct

    然后 ctrl shift p  

    输入>go:install

    选择Go:Install/Update Tools这个命令,

    Go 的编译:

    进入项目目录中,执行go mod init  此时会生成 go.mod  ,

    然后使用  go build 就生成了一个可执行文件, 

    Go 的Hello world:

    package main
    import "fmt"
    
    func main() {
        fmt.Println("Hello world")
    
    }

    Go mod 常见错误 解决:

            gopkg.in/russross/blackfriday.v2: gopkg.in/russross/blackfriday.v2@v2.0.1: parsing go.mod:
            module declares its path as: github.com/russross/blackfriday/v2
                    but was required as: gopkg.in/russross/blackfriday.v2 (找不到它)
    
    
    replace gopkg.in/russross/blackfriday.v2 => github.com/russross/blackfriday/v2 v2.0.1

    Go 基础知识:

    Go 标识符 和 关键字 和 保留字

    Go语言中标识符由字母数字和_(下划线)组成,并且只能以字母和_开头。

    查看数据类型: 

    a := 1.23456
    fmt.Printf("%T
    ", a)

    %v 万能占位符,

    a:= 10
    fmt.Printf("%v 
    ", a)
    b:= "tom"
    fmt.Printf("%v 
    ", b)
    
    c:= false
    fmt.Printf("%v 
    ", c)
        a:= 10
        fmt.Printf("%#v 
    ", a)
        b:= "tom"
        fmt.Printf("%#v 
    ", b)
    
        c:= false
        fmt.Printf("%#v 
    ", c)
    %#v

    统计字符串中汉字的数量: 

    package main
    
    import (
        "fmt"
        "unicode"
    )
    func main() {
        s := "hello世界,我靠无情"
        count := 0
        for _,c := range s{
            if unicode.Is(unicode.Han,c){
                count += 1
            }
        }
        fmt.Println(count)
    }
    View Code

    go 语言for 循环实现 九九乘法表:  

    package main
    
    import "fmt"
    
    func main() {
        for i:=0;i<9;i++ {
            for j:=0;j<=i;j++ {
                fmt.Printf("%d x %d = %d  ",i+1,j+1,(i+1)*(j+1))
            }
            fmt.Println()
        }
    }
    View Code

    go 指针:

    go 中的指针:

    go的指针不支持 指针计算   

    指针的类型:

    * int  

    * [2]int  

    指针数组 : [3]*int  ,[3]*string ,[3]*(* int)

    数组指针 : *[3]int *[3]string , 

    多级指针:

    package main
    
    import "fmt"
    
    func main() {
    
        a := 1
        b := 2
        arr := [...]*int{&a,&b}
        fmt.Println(arr)
    
        c := &a
        d := &b
        arr2 := [...]**int{&c,&d}
        fmt.Println(arr2)
    
        for _,val :=range arr2{
            fmt.Println(*val)
        }
    
        for _,val :=range arr{
            fmt.Println(*val)
        }
    
    
    
    }

    Go  中的new  :

    new 和 make的区别:  

    package main
    
    import "fmt"
    
    func main() {
    
        var ptr *int
        fmt.Println(ptr)
        //fmt.Println(*ptr) // 报错
    
        ptr = new(int)
        fmt.Println(ptr)
        fmt.Println(*ptr)
    
        // make 和 new 的区别
        // 1,都是 用来申请内存的
        // 2,make 是用来给 slice ,map ,chan 申请内存,它返回是 它们类型本身
        // 3,new 一般是给基本数据类型申请内存,它返回是指针
    
    }
    new 和 make

    map 按照 value 排序: 

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    func main() {
        m := make(map[string]int,10) 
    
        for i:=0;i<5;i++ {
            m["age"+strconv.Itoa(i)] = 10 + i
        }
        m["age10"] = 20
        m["age11"] = 6
    
        // 下面对 m 按照 val 排序
        keys := make([]string,0,10)
        for k :=range m{
            keys = append(keys,k)
        }
    
        // 冒泡 排序
        for i:=0;i<len(keys) - 1;i++{
            for j:=0;j<len(keys) -1 -i;j++{
                if m[keys[j]] > m[keys[j+1]]{
                    temp := keys[j]
                    keys[j] = keys[j+1]
                    keys[j+1] = temp
                }
            }
        }
        for _,key := range keys{
            fmt.Println(key,m[key])
        }
    }
    View Code

    Go 的函数传参永远是 值传递:

    new  结构体  得到指针,

    var 结构体 得到的是值

    package main
    
    import "fmt"
    
    type Person struct { // 这是自定义类型  自定义了Person 这个类型
        name string
        age int
    }
    func test(p *Person)  { // go 函数传参永远是 值传递
        //(*p).name = "jane"
        p.name = "jane" // 和上面的写法一样  
    }
    
    func main(){
    
        //var p Person
        p := new(Person)
        p.name = "tom"
        p.age = 18
        fmt.Println(p.name)
        test(p)
        fmt.Println(p.name)
    }
    View Code

    go 的 “类” 构造函数 和方法 :

     1 package main
     2 
     3 import "fmt"
     4 
     5 type Person struct { // 这是自定义类型  自定义了Person 这个类型
     6     name string
     7     age int
     8 }
     9 // Person 的构造函数
    10 func personConstructor(name string,age int) *Person {
    11     return &Person{
    12         name:name,
    13         age:age,
    14     }
    15 }
    16 // Person 的方法
    17 func (p *Person)run()  {
    18     fmt.Println("I am run,My name's:",p.name)
    19 }
    20 
    21 func main(){
    22     p := personConstructor("tom",18)
    23     p.run()
    24 }
    go的 构造函数 和 方法

    go 自定义类型:

    给 int 类型加个方法 

    package main
    
    import "fmt"
    
    type myInt int
    func (i myInt) hello(){
        fmt.Println("我是一个Int")
    }
    
    func main(){
        var a myInt
        a = 10
        a.hello()
        fmt.Println(a)      
    }
    View Code

    go 的 “继承” 

    package main
    
    import "fmt"
    
    type Animal struct {
        name string
    }
    func (animal *Animal)move(){
        fmt.Println("I am moving!")
    }
    
    type Dog struct {
        name string
        *Animal // 通过嵌套匿名结构体的方式 实现 “ 继承 ”
    }
    
    func main(){
        var dog = new(Dog)
        dog.move()
    
        
    }
    通过嵌套匿名结构体的方式 实现 “ 继承 ”

    结构体 与 JSON 互转 

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type Person struct {
        Name string
        Age int
    }
    
    func main(){
        var p = new(Person)
        p.Name = "tom"
        p.Age = 18
    
        // 序列化
        ret,err := json.Marshal(p)
        fmt.Println(err)
        fmt.Println(string(ret))
    
        // 反序列化
        var p2 = new(Person)
        json.Unmarshal(ret,&p2)
        fmt.Println(p2)
        fmt.Println(p2.Name)
        fmt.Println(p2.Age)
    
    }
    Go中的序列化 和 反序列化

    go 利用接口实现多态:

    package main
    
    import "fmt"
    
    type myInterface interface {
        eat()
    }
    type Person struct {}
    func (p *Person)eat(){
        fmt.Println("人吃饭")
    }
    
    type Dog struct {}
    func (d *Dog)eat(){
        fmt.Println("狗吃饭")
    }
    
    func eat(obj myInterface)  { // 多态
        obj.eat()
    }
    
    
    
    func main() {
        p := new(Person)
        d := new(Dog)
    
        eat(p)
        eat(d)
    
    
    }
    View Code

    go 接口:

    查看一个对象是否实现了一个接口(实现接口中所有的方法):

    package main
    
    import (
        "fmt"
    )
    
    type Animal interface {
        Say()
    }
    type Dog struct {}
    
    func (d *Dog)Say()  {
        fmt.Println("Dog say")
    }
    
    func main()  {
    
        d := Dog{}
        var xxx interface{} = &d
        _,ok := xxx.(Animal) // d 必须实现 Animal 接口中所有的方法时 才为true 
        fmt.Println(ok)
        if ok{
            d.Say() 
        }
    }
    View Code

    空接口:

    任何 类型的变量都实现了 空接口 ,

    空接口类型 , 

    package main
    
    import "fmt"
    
    func main() {
        // map 的value 类型是 空接口类型
        m := make(map[string]interface{})
        m["name"] = "tom"
        m["age"] = 18
        m["hobby"] = []string{"basketball","movie"}
    
        fmt.Println(m)
        for k,v := range m {
            fmt.Println(k,v)
        }
    
    }
    View Code

    空接口类型 形参:

    package main
    
    import (
        "fmt"
    )
    
    func myPrint(obj interface{})  {
        fmt.Println(obj)
    }
    
    func main() {
        myPrint("tom")
        myPrint(18)
        myPrint([]string{"tom","jack"})
        myPrint([...]int{1,2,3})
        myPrint(struct {
            name string
            age int
        }{name: "tom",age: 18})
    
    }
    View Code

    空接口 类型断言:

    package main
    
    import "fmt"
    
    func myPrint(obj interface{})  {
        s,ok := obj.(string)
        if ok{
            fmt.Println("此时的 s 就是 string 类型了,就不是 接口类型了")
            fmt.Println(s)
        }else{
            fmt.Println("非 string 类型")
        }
    
    
    
    }
    
    func main() {
        myPrint("tom")
        myPrint(18)
        myPrint([]string{"tom","jack"})
        myPrint([...]int{1,2,3})
        myPrint(struct {
            name string
            age int
        }{name: "tom",age: 18})
    
    }
    .(type) 断言

    判断存在key 且 为 string 类型:

    ret,ok := ctx.Input.Session("age").(string) // 存在age  并且要求 age 为 string 类型,否则返回false  
    View Code

    swith 结合 空接口:

    package main
    
    import "fmt"
    
    func myPrint(obj interface{})  {
        switch obj.(type) {
        case string:
            fmt.Println("是个string类型")
        case int:
            fmt.Println("是个int 类型")
        default:
            fmt.Println("其他")     
        }
    }
    
    func main() {
        myPrint("tom")
        myPrint(18)
        myPrint([]string{"tom","jack"})
        myPrint([...]int{1,2,3})
        myPrint(struct {
            name string
            age int
        }{name: "tom",age: 18})
    
    }
    View Code

    点括号的用法(类型转换):

    接口变量调用

    package main
    
    import "fmt"
    
    // Sayer 接口
    type Sayer2 interface {
        say()
    }
    type dog struct {}
    type cat struct {}
    // dog实现了Sayer接口
    func (d dog) say() {
        fmt.Println("汪汪汪")
    }
    // cat实现了Sayer接口
    func (c cat) say() {
        fmt.Println("喵喵喵")
    }
    func main() {
        var x Sayer2 // 声明一个Sayer类型的变量x
        ret := x.(dog) // 将 接口变量x  的类型从 Sayer2 转为 dog 
        ret.say() 
    }
    View Code

    go 文件操作:

    读文件:

    使用的是os.Open() 

    bufio:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func main()  {
        fp,err := os.Open("zcb.go")
        if err != nil{
            fmt.Println("open file error")
            return
        }
        defer fp.Close()
    
        reader := bufio.NewReader(fp)
        for  {
            line,err := reader.ReadString('
    ')
            if err == io.EOF{
                if len(line)!=0{
                    fmt.Print(line)
                }
                fmt.Println("我读完了")
                break
            }
            if err != nil{
                fmt.Println("read file err")
                return
            }
    
            fmt.Print(line)
        }
    
    }
    一行一行的读

    ioutil:

    读取整个文件: 

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "os"
    )
    
    func main()  {
        fp,err := os.Open("zcb.go")
        if err != nil{
            fmt.Println("open file error")
            return
        }
        defer fp.Close()
        content,err := ioutil.ReadFile("zcb.go")
        if err != nil{
            fmt.Println("read file error")
            return
        }
        fmt.Println(string(content))
    }
    View Code

    写文件:

    使用的是 os.OpenFile()

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main()  {
        /*
            os.O_WRONLY|os.O_CREATE|os.O_APPEND 只写 append 没有时创建
            os.O_WRONLY|os.O_CREATE|os.O_TRUNC  只写  没有时创建,有时直接清空
        */
        fp,err := os.OpenFile("test.text",os.O_WRONLY|os.O_CREATE|os.O_TRUNC,0666)
        if err != nil{
            fmt.Println("file open err")
        }
        defer fp.Close()
    
        _,err2 := fp.WriteString("hello world 世界你好啊")
        if err2 != nil{
            fmt.Println("write file err")
        }
    
    
    
    }
    View Code

    读取用户输入:

    如果用scan 的话,无法读取用户输入的空格数据,例如hello world 只能是 hello,

    package main
    
    import "fmt"
    
    func main()  {
        var motto string
        _,err := fmt.Scan(&motto) // 此时如果用户 hello world  
        if err != nil{
            fmt.Println("读取用户输入 失败")
        }
        fmt.Println(motto)
    
    }
    View Code

    所以这里可以使用bufio  

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main()  {
        reader := bufio.NewReader(os.Stdin)
        res,err := reader.ReadString('
    ')
        if err!= nil{
            fmt.Println("读取用户输入 失败")
        }
        fmt.Println(res)
    }
    从标准输入 来读取用户的输入

    自定义 日志 包:

    需求分析:

    日志的四种级别:DEBUG INFO WARN ERROR

    可以向不同位置写日志

    支持开关控制(例如,上线后,只有WARN 和 ERROR 才可以输出  )

    支持日志文件切割

    完整日志记录包含时间,行号,文件名,级别,日志信息

    切割文件时:

    https://files.cnblogs.com/files/zach0812/%E7%AE%80%E5%8D%95%E6%97%A5%E5%BF%97%E5%8C%85go%E8%AF%AD%E8%A8%80.zip

    异步收集日志功能实现: 

    https://files.cnblogs.com/files/zach0812/%E5%BC%82%E6%AD%A5%E6%94%B6%E9%9B%86%E6%97%A5%E5%BF%97%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0_go%E8%AF%AD%E8%A8%80.zip

    go 并发:

    1,goroutine 

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func hello(i int){
        defer wg.Done()
        fmt.Println("hello ",i)
    }
    
    func main() {
        for i:=0;i<1000;i++{
            wg.Add(1)
            go hello(i)
        }
        fmt.Println("main")
        wg.Wait()
    }
    goroutine 和 sync.WaitGroup

    2,channel 类型

    必须使用make 初始化,(slice , map,channel 都要用 make 分配内存)

    func main() {
        var wg sync.WaitGroup
    
        ch1 := make(chan int,2)
        for i:=0;i<2;i++{
            ch1 <- i
        }
        wg.Add(1)
        go func(ch chan int) {
            defer wg.Done()
            time.Sleep(time.Second)
            x := <- ch
            fmt.Println(x)
        }(ch1)
        ch1 <- 10  // 已经满了,此时会阻塞 在这里~  
        fmt.Println("hello world")
    
        wg.Wait()
    }
    View Code

    worker pool (goroutine 池):

    func worker(id int, jobs <-chan int, results chan<- int) {
        for j := range jobs {
            fmt.Printf("worker:%d start job:%d
    ", id, j)
            time.Sleep(time.Second)
            fmt.Printf("worker:%d end job:%d
    ", id, j)
            results <- j * 2
        }
    }
    
    
    func main() {
        jobs := make(chan int, 100)
        results := make(chan int, 100)
        // 开启3个goroutine
        for w := 1; w <= 3; w++ {
            go worker(w, jobs, results)
        }
        // 5个任务
        for j := 1; j <= 5; j++ {
            jobs <- j
        }
        close(jobs)
        // 输出结果
        for a := 1; a <= 5; a++ {
            <-results
        }
    }

    需求01:

    //使用goroutine和channel实现一个计算int64随机数各位数和的程序。
    //开启一个goroutine循环生成1000个 int64类型的随机数,发送到jobChan
    //开启24个goroutine从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
    //主goroutine从resultChan取出结果并打印到终端输出
    package main
    
    import (
        "fmt"
        "math/rand"
        "sync"
    )
    
    func getInt64Sum(b int64) int {
        ret := int64(0)
        for  {
            ret += b % 10
            temp := b/10
            if temp  == 0{
                break
            }
            b = temp
        }
        return int(ret)
    }
    
    func worker(jobs <-chan int64, results chan <-int)  {
        defer wg.Done()
        for item := range jobs {
            results <- getInt64Sum(item)
        }
    }
    var wg sync.WaitGroup
    
    func main() {
        jobs := make(chan int64,1000)
        results := make(chan int,1000)
    
        wg.Add(1)
        go func() { // 开启一个goroutine 放1000个int64 的数 到jobs 中
            defer wg.Done()
            for i:=0;i<100;i++{
                ret := rand.Int63()
                jobs <- ret
            }
            close(jobs)
        }()
    
        // 开启24 个goroutine 去处理 jobs 的内容,并将结果放到 results 中
        for i:=0;i<24;i++ {
            wg.Add(1)
            go worker(jobs,results)
        }
        wg.Wait()
        close(results)
    
        for res := range results{
            fmt.Println(res)
        }
    }
    View Code

    需求02:

    不断生成随机数,一直处理一直输出到终端

    package main
    
    import (
        "fmt"
        "math/rand"
        "sync"
        "time"
    )
    
    func getInt64Sum(b int64) int {
        ret := int64(0)
        for  {
            ret += b % 10
            temp := b/10
            if temp  == 0{
                break
            }
            b = temp
        }
        return int(ret)
    }
    
    func worker(jobs <-chan int64, results chan <-int)  {
        defer wg.Done()
        for item := range jobs {
            results <- getInt64Sum(item)
        }
    }
    var wg sync.WaitGroup
    
    func main() {
        jobs := make(chan int64,1000)
        results := make(chan int,1000)
    
        wg.Add(1)
        go func() {
            defer wg.Done()
            for {
                time.Sleep(100*time.Millisecond)  // 0.1s 生成一个
                ret := rand.Int63()
                jobs <- ret
            }
        }()
    
        // 开启24 个goroutine 去处理 jobs 的内容,并将结果放到 results 中
        for i:=0;i<24;i++ {
            wg.Add(1)
            go worker(jobs,results)
        }
    
        for res := range results{
            fmt.Println(res)
        }
    
        wg.Wait()
    }
    View Code

    go   socket编程 :

    osi 七层: 应表会 传  网 数物

    socket 通信

    1,简单版:

    server 端:

    package main
    
    import (
        "fmt"
        "net"
    )
    
    /*tcp server*/
    func main()  {
        // 1 监听端口
        listener,err := net.Listen("tcp","127.0.0.1:8000")
        if err != nil {
            fmt.Println("tcp server listen 127.0.0.1:8000 failed,err:",err)
            return
        }
        // 2 等待客户端来连接
        conn,err :=  listener.Accept()
        if err != nil {
            fmt.Println("tcp server accept failed ,err:",err    )
            return
        }
        // 3 通信
        var ret [128]byte
        n,err := conn.Read(ret[:])
        if err != nil {
            fmt.Println("tcp server conn read failed ,err",err)
            return
        }
        fmt.Println(string(ret[:n]))
    
    
    }
    View Code

    client端

    package main
    
    import (
        "fmt"
        "net"
    )
    
    /*tcp client*/
    
    func main() {
    
        // 1 连接 服务端
        conn,err := net.Dial("tcp","127.0.0.1:8000")
        if err != nil {
            fmt.Println("tcp client dial failed ,err:",err)
            return
        }
        // 2 通信
        temp := "Hello server,I'm client! 你好啊"
        _,err = conn.Write([]byte(temp))
        if err != nil {
            fmt.Println("tcp client write failed ,err:",err)
        }
        conn.Close()
    
    }
    View Code

    2,升级版:

    server 端:

    package main
    
    import (
        "fmt"
        "net"
    )
    
    func processConn(conn net.Conn){
        // 3 通信
        var ret [128]byte
        n,err := conn.Read(ret[:])
        if err != nil {
            fmt.Println("tcp server conn read failed ,err",err)
            return
        }
        fmt.Println(string(ret[:n]))
    
    }
    
    
    /*tcp server*/
    func main()  {
        // 1 监听端口
        listener,err := net.Listen("tcp","127.0.0.1:8000")
        if err != nil {
            fmt.Println("tcp server listen 127.0.0.1:8000 failed,err:",err)
            return
        }
        for  {
            // 2 等待客户端来连接
            conn,err :=  listener.Accept()
            if err != nil {
                fmt.Println("tcp server accept failed ,err:",err    )
                return
            }
            go processConn(conn)
        }
    
    
    }
    View Code

    client 端:

    同上,

    tcp 粘包 现象:

    大端和 小端:

    当一个变量是多个字节的时候会存在大端小端的问题,

    该变量在内存中从左开始,依次高位到低位,为 大端

    从 右开始,依次高位到低位,为 小端 

    开发人员 需要注意的东西:

    注释日志单元测试 

    go net/http 包:

    package main
    
    import "net/http"
    
    func f1(w http.ResponseWriter, r * http.Request)  {
        s := "Welcome come to my site."
        w.Write([]byte(s))
    }
    
    
    
    func main()  {
    
        http.HandleFunc("/index",f1)
        http.ListenAndServe("127.0.0.1:8000",nil)
    
    }
    http server端

    http client 端
    就是爬虫,

    package main
    
    import (
        "fmt"
        "io/ioutil"
        "net/http"
    )
    
    func main()  {
        response ,_ := http.Get("http://127.0.0.1:8000/index")
        fmt.Println(response.Status)
        fmt.Println(response.Body)
    
        defer response.Body.Close()
        ret ,_ := ioutil.ReadAll(response.Body)
        fmt.Println(string(ret)    )
    }
    View Code

    go   单元测试 :

    pass 

    go 获取本地的ip:

    package main
    
    import (
        "fmt"
        "net"
        "strings"
    )
    
    // 获取本地对外的IP
    func GetOutBoundIP()(ip string,err error){
        conn,err := net.Dial("udp","8.8.8.8:80")
        if err != nil {
            return
        }
        defer conn.Close()
        localAddr := conn.LocalAddr().(*net.UDPAddr)
        fmt.Println(localAddr.String())
        ip = strings.Split(localAddr.IP.String(),":")[0]
        return
    }
    
    func main()  {
        ip,err := GetOutBoundIP()
        fmt.Println(ip)
        fmt.Println(err)
    }
    View Code

    Go 项目:

    go 操作mysql :

    安装驱动 :

    1,go mod init main.go

    2,go get -u github.com/go-sql-driver/mysql

    package main
    
    import (
        "database/sql"
        "fmt"
        _ "github.com/go-sql-driver/mysql"
    )
    
    func main() {
    
        // database source name 数据库信息
        dsn := "root:123456@tcp(127.0.0.1:3306)/go_mysql"
    
        db, err := sql.Open("mysql", dsn)
        if err != nil {
            fmt.Printf("dsn :%s format err,err : %v 
    ", dsn, err) // 并不会真正校验 是否成功连接 只是校验 格式是否正确
            return
        }
    
        err = db.Ping() // 此时 会真正校验是否能成功连接
        if err != nil {
            fmt.Printf("open %s failed,err: %v 
    ", dsn, err)
            return
        }
    
        fmt.Println("connection success ")
    
    }
    简单连接到mysql
    package main
    
    import (
        "database/sql"
        "fmt"
        _ "github.com/go-sql-driver/mysql"
    )
    var db *sql.DB
    
    type user struct { // user 表对应的结构体
        id int
        name string
        age int
    }
    
    func initDB() error {
        // database source name 数据库信息
        dsn := "root:123456@tcp(127.0.0.1:3306)/sql_test"
    
        var err error
        db, err = sql.Open("mysql", dsn)
        if err != nil {
            return err
        }
    
        err = db.Ping() // 此时 会真正校验是否能成功连接
        if err != nil {
            return err
        }
    
    
        db.SetMaxOpenConns(10) // 设置数据库连接池的 最大连接数
        db.SetMaxIdleConns(5) // 最大闲置的 连接数
    
    
        return nil
    }
    
    // 查询单个记录
    func queryOne(id int)  {
        sqlStr := `select id,name,age from user where id=?;`
        var u user
        //rowObj := db.QueryRow(sqlStr,id)
        //err := rowObj.Scan(&u.id,&u.name,&u.age) // 注:必须要 Scan 其内部有 defer 用于 释放连接
    
        err := db.QueryRow(sqlStr,id).Scan(&u.id,&u.name,&u.age) // 为了防止忘记,上面的可以直接写为 一行
        if err != nil {
            fmt.Printf("query failed,err:%v
    ",err)
            return
        }
        fmt.Println(u)
    }
    
    // 查询多个记录
    func queryMany(id int)  {
        sqlStr := `select id,name,age from user where id >= ?;`
        rows,err := db.Query(sqlStr,id)
        if err != nil {
            fmt.Printf("exec %s query failed,err :%v
    ", sqlStr, err)
            return
        }
        defer rows.Close() // 一定要关闭 rows
    
        // 循环取值
        for rows.Next(){
            var u user
            err := rows.Scan(&u.id,&u.name,&u.age)
            if err != nil {
                fmt.Printf("scan rows failed,err :%v
    ", err)
                return
            }
            fmt.Println(u)
        }
    
    
    }
    
    // 插入数据 删除数据  更新数据 都是用 db.Exec()  查询用的是 db.Query
    func insert()  {
        sqlStr := `insert into user(name,age) values("jane",38)`
        res,err := db.Exec(sqlStr)
        if err != nil {
            fmt.Printf("exec sqlStr:%s failed,err :%v
    ",sqlStr,err)
            return
        }
        // 如果是插入数据,可以从res 拿到最后一个的id
        id,err := res.LastInsertId()
        if err != nil {
            fmt.Printf("get last insert id failed,err:%v
    ", err)
            return
        }
        fmt.Println(id)
    
    
    
    
    
    }
    
    
    func main() {
        err := initDB()
        if err != nil {
            fmt.Printf("init DB failed,err :%v
    ",err)
            return
        }
        fmt.Println("connection success ")
    
        //// 1 查询单条记录
        //queryOne(1)
    
        // 2 查询多条记录
        //queryMany(1)
    
        // 增 删 改
        insert()
    
    
    }
    增删改查

    注: sqlx 查询的时候 更方便一点,需要安装 go get github.com/jmoiron/sqlx 

    go 操作redis:

    go get -u github.com/go-redis/redis

    go 操作nsq:

    NSQ是目前比较流行的一个分布式的消息队列

    如何退出 子goroutine :

    1,定义全局变量 

    2,利用通道 (如果能从 通道中取到值 就退出,)

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func f()  {
        defer wg.Done()
    
    FORLOOP:for  {
            fmt.Println("hello go")
            time.Sleep(500*time.Millisecond) // 0.5s
            select {
            case <- exitChan:
                break FORLOOP // 退出 for 循环
            default:
            }
        }
    }
    
    var wg sync.WaitGroup
    var exitChan =make(chan struct{},1)
    
    func main()  {
        wg.Add(1)
        go f()
        time.Sleep(5*time.Second) // 5s
        exitChan <- struct {}{}  // 退出子 goroutine
        wg.Wait()
    }
    View Code

    3,使用context   退出

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    
    func f(ctx context.Context)  {
        defer wg.Done()
    
    FORLOOP:for  {
            fmt.Println("hello go")
            time.Sleep(500*time.Millisecond) // 0.5s
            select {
            case <- ctx.Done():
                break FORLOOP // 退出 for 循环
            default:
            }
        }
    }
    
    var wg sync.WaitGroup
    
    func main()  {
        ctx,cancel := context.WithCancel(context.Background())
        wg.Add(1)
        go f(ctx)
        time.Sleep(5*time.Second) // 5s
        cancel()
        wg.Wait()
    }
    View Code

    并且可以一个cancel 可以退出 多层的 子 goroutine  

    package main
    
    import (
        "context"
        "fmt"
        "sync"
        "time"
    )
    func f2(ctx context.Context)  {
        defer wg.Done()
    
    FORLOOP:for  {
        fmt.Println("hello go in f2")
        time.Sleep(500*time.Millisecond) // 0.5s
        select {
        case <- ctx.Done():
            break FORLOOP // 退出 for 循环
        default:
        }
    }
    }
    
    
    func f(ctx context.Context)  {
        defer wg.Done()
        go f2(ctx)
    
        FORLOOP:for  {
            fmt.Println("hello go in f1")
            time.Sleep(500*time.Millisecond) // 0.5s
            select {
            case <- ctx.Done():
                break FORLOOP // 退出 for 循环
            default:
            }
        }
    }
    
    var wg sync.WaitGroup
    
    func main()  {
        ctx,cancel := context.WithCancel(context.Background())
        wg.Add(1)
        go f(ctx)
        time.Sleep(5*time.Second) // 5s
        cancel()
        wg.Wait()
    }
    /*
    hello go in f1
    hello go in f2
    hello go in f2
    hello go in f1
    hello go in f1
    hello go in f2
    hello go in f1
    hello go in f2
    hello go in f2
    hello go in f1
    hello go in f1
    hello go in f2
    hello go in f2
    hello go in f1
    hello go in f1
    hello go in f2
    hello go in f2
    hello go in f1
    hello go in f1
    hello go in f2
    */
    View Code

    时间相关:

    func test()  {
        // 加载时区
        loc, err := time.LoadLocation("Asia/Shanghai")
        if err != nil {
            fmt.Println(err)
            return
        }
    
        now := time.Now()
    
        // 1 表示下 2020.02.02 这个时间
        t := time.Date(2020,2,2,0,0,0,0,loc)
        //fmt.Println(t)
    
        // 2 现在时间距离 20200202 过去了多久
        ret := now.Sub(t)
        fmt.Printf("%f天
    ",ret.Hours()/24)
    
        // 3 一年前的时间
        t2 := now.Add(-365*24*time.Hour)
        fmt.Println(t2)
    
        // 4 一年后的时间
        t3 := now.Add(365*24*time.Hour)
        fmt.Println(t3)
    
    }
    View Code

    网络编程:

    osi 七层:

    Open System Interconnection

    开放式系统互联是把网络通信的工作分为7层,分别是物理层,数据链路层,网络层,传输层,会话层,表示层和应用层。

    osi 七层 与 各协议的对照表:

  • 相关阅读:
    springcloud(3)consul
    springcloud(2)服务提供者配置及集群和信息显示改善
    springcloud(1)Eureka配置及集群
    Git操作和配合GitHub进行代码托管
    GitHub的基本使用
    关于mybatis的各种绑定(bind)错误,找不到类的情况
    springboot整合thymeleaf视图解析器
    spring boot 源码分析-------ApplicationContext
    https原理
    单例模式
  • 原文地址:https://www.cnblogs.com/zach0812/p/12736607.html
Copyright © 2011-2022 走看看