Go语言入坑

GO语言基础

认识并安装GO语言开发环境

Go语言简介
  • Go语言是谷歌2009年发布的第二款开源编程语言

  • go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全,支持并行进程

Go语言特点
  • 简洁、快速、安全

  • 并行、有趣、开源

  • 内存管理,数组安全,编译迅速

Go语言开发的应用
  • docker

  • Codis(豆瓣开发的大部分使用go语言)

  • Glow类似于hadoop

  • cockroach

一些见解
  • Java语言的份额继续下滑,并最终被C和Go语言超越;

  • C语言将长居编程榜第二的位置,并有望在Go取代java前重获语言榜第一的宝座

  • Go语言最终会取代java,居于编程榜之首

Go语言环境搭建
  • go源码安装

  • go标准包安装

  • 第三方工具安装 比如GVM

  • go语言开发工具

    • LiteIDE

    • IDE

    • eclipese、sublime

GO语言基础知识

第一个Go应用HelloWord
  • package main
    import "fmt"
    func main(){
    //go语言不强制加分号
    fmt.Print("Hello word")
    }
    //cmd输入 go run hello.go输出结果
配置
  • go语言依赖一个重要得环境变量:$GOPATH(不是安装目录)

    • 使用go get github.com/astaxie/beego命令下载框架失败,是因为未配置gopath

    • set GOPATH=e:/go_path:设置gopath路径

    • echo %GOPATH%:查看gopath路径

    • gopath得作用

      • 下载第三方代码

      • 包管理与引用

      • gopath多个包调用代码练习

Go语言常用关键字
  • break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var

    • package main下得main()函数是go语言得入口

    • var:关键字是go最基本得定义变量的方式,与C语言不同的是Go把变量类型放在变量名后面

      • 例:var x int
Go语言开发工具liteide
  • 创建应用编译

  • y:="hello" //简短声明的使用,可定义多个

  • 代码:

    • package main

      import "fmt"

      func main() {
      var x int
      x = 1
      //这种用法须在函数体内
      y, z := "go demo", 2
      fmt.Printf("%d %s %d", x, y, z)
      }
go语言数据类型
  • bool

  • runne

  • int8、int16、int32、int64

  • byte

  • unit8、unit16、unit32、unit64

  • flot32、float64

  • complex64、complex128

  • string

  • array slice

  • map

其它基础
  • 数组的定义

  • 其它数据类型的使用

  • s:=make([]int,10,20)//slice动态数组对象

  • map:student:=make(map[string]int)

    • make用于内建类型(map、slice、channel)的内存分配
  • 流程控制语句

    • if语句

    • for

      • func main() {
        sum := 0
        x := 1
        for x <= 100 {
        sum += x
        x++
        }
        fmt.Print(sum)
        }
    • switch

      • x:=1
        switch x{
        case 1:
        fmt.Print("demo1")
        //GO默认添加了break
        break
        case 2:
        //继续需要添加
        fallthrough
        case 3:
        fmt.Print("demo2")
        break
        default 3:
        fmt.Print("demo3")
        }
    • for循环

      • x := [5]int{1, 2, 3, 4, 5}
        for i, v := range x {
        fmt.Println(i, v)
        }
        x := make(map[string]int)
        x["zhangsan"] = 78
        x["lisi"] = 90
        x["wangwu"] = 100
        for i, v := range x {
        fmt.Println(i, v)
        }
        x := "zhangsan"
        for _, v := range x {
        fmt.Printf("%c\n", v)
        }
  • Go语言函数

    • func funcName(input1 type1,input2 type2)(output1 type1,output2 type2){
      //逻辑处理代码
      //返回多个值
      return value1,value2
      }
      package main

      import "fmt"

      func swap(a int, b int) (int, n int) {
      return b, a
      }
      func main() {
      a := 1
      b := 2
      a, b = swap(a, b)
      fmt.Printf("%d %d", a, b)
      }
      //匿名函数
      f:=func(x,y int)int{
      return x+y
      }
      fmt.Println(f(2,3))

    • go语言中指针的概念

    • defer关键词使执行顺序倒着走,退出或资源关闭时使用

      • defer func() {
        fmt.Println("After defer")
        }()
        fmt.Println("befor defer")
        //defer语句遇到异常继续执行
  • Go语言结构struct

    • package main
      import "fmt"
      type Person struct {
      name string
      age int
      }
      type Student struct{
      Person//匿名字段,使用和类包含类似
      speciality string
      }
      func main() {
      person := Person{"zhangsan", 25}
      // person2 :=Person{age:25,name:"wangwu"}//指定字段赋值
      fmt.Printf("%v", person)
      }

GO语言面向对象

类的定义与使用
  • 简单定义使用

    • package main

      import "fmt"

      type Integer struct {
      value int
      }

      func (a Integer) compare(b Integer) bool {
      return a.value < b.value
      }
      func main() {
      // var a int =1
      // var b int =2
      a := Integer{1}
      b := Integer{2}
      fmt.Printf("%v", a.compare(b))
      }
  • go中类的初始化

    • point:=new(Point)
      point:=&Point{}
      point:=&Point{x:100,y:100}
      point:=Point{}

    • 定义与使用示例

      • package main
        import "fmt"
        type Point struct {
        px float32
        py float32
        }
        func (point *Point) setxy(px, py float32) {
        point.px = px
        point.py = py
        }
        func (point *Point) getxy() (float32, float32) {
        return point.px, point.py
        }
        func main() {
        point := new(Point)
        point.setxy(1.24, 4.25)
        px, py := point.getxy()
        fmt.Print(px, py)
        }
类的继承与使用
  • package main

    import "fmt"

    type Person struct {
    name string
    age int
    }

    func (person Person) getNameAndAge() (string, int) {
    return person.name, person.age
    }

    type Student struct {
    Person
    speciality string
    }

    func (student Student) getSpeciality() string {
    return student.speciality
    }
    func main() {
    student := new(Student)
    student.name = "zhangsan"
    student.age = 26
    name, age := student.getNameAndAge()
    fmt.Println(name, age)
    }

  • Go语言接口

    • 在go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口

      • package main

        import "fmt"
        //非侵入式接口
        type Animal interface {
        Fly()
        Run()
        }
        type Animal2 interface {
        Fly()
        }
        type Bird struct {
        }
        func (bird Bird) Fly() {
        fmt.Println("bird is flying")
        }
        func (bird Bird) Run() {
        fmt.Println("bird is Run")
        }
        func main() {
        var animal Animal
        var animal2 Animal2
        bird := new(Bird)
        animal = bird
        animal2=bird
        animal2.FLy()
        animal2=animal//在GO中可以接口赋值
        animal.Fly()
        animal.Run()
        }
    • 在Go语言中空间口类似泛型

      • var v1=interface{}
        v1=6.78
        fmt.Print(v1)
        //类型查询,看接口接收的什么类型
        if v, ok := v1.(float64); ok {
        fmt.Println(v, ok)
        }

GO语言进阶

GO语言并发编程

Go语言并发编程之协程
  • 与传统的系统级线程相比,协程的大优势在于其"轻量级",可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程通常多也不能超过1万个,这也是协程也叫轻量级线程的原因.

  • go对协程的实现:go+函数名:启动一个协程执行函数体

    • package main
      import (
      "fmt"
      "time"
      )
      func test_Routine() {
      fmt.Println("This is one routine!")
      }
      func main() {
      go test_Routine()
      time.Sleep(1)
      }
  • Go并发编程之channel

    • Channel:Go语言在语言级别提供的goroutine间的通讯方式

      • 声明方式:var chanName chan ElementType

        • package main

          import (
          "fmt"
          "strconv"
          )

          func Add(x, y int, quit chan int) {
          z := x + y
          fmt.Println(z)
          quit <- 1
          }
          func Read(ch chan int) {
          value := <-ch
          fmt.Println("value:" + strconv.Itoa(value))
          }
          func Write(ch chan int) {
          // ch < -10
          }
          func main() {
          chs := make([]chan int, 10)
          for i := 0; i < 10; i++ {
          chs[i] = make(chan int)
          go Add(i, i, chs[i])
          }
          for _, v := range chs {
          <-v
          }
          }
    • 缓存channel

      • package main

        import (
        "fmt"
        "time"
        )

        var ch chan int

        func test_channel() {
        // ch := make(chan int)
        ch <- 1
        fmt.Println("come to end goroutline 1")
        }
        func main() {
        ch = make(chan int, 2) //值是1和值是0的适合输出执行顺序不同
        go test_channel()
        time.Sleep(2 * time.Second)
        fmt.Println("running end!")
        <-ch
        time.Sleep(time.Second)
        }

    • select

      • 是linux很早就引入的函数,用来实现非阻塞的一种方式

      • go语言提供语言级别支持slelect关键字,用于处理异步IO问题

        • select{
          case <-chan1://如果chan1成功读取到数据,则进行该case处理语句
          case chan2 <-1://如果成功向chan2写入数据,则进行该case处理
          default: //如果上面都没有成功,则进入default处理流程
          }
      • select 三个代码示例

        • 示例1

          package main

          import (
          "fmt"
          "time"
          )

          func main() {
          ch := make(chan int)
          go func(ch chan int) {
          ch <- 1
          }(ch)
          // time.Sleep(2)//加这一句执行结果不同
          select {
          case <-ch:
          fmt.Print("come to read ch!")
          default:
          fmt.Print("come to default!")
          }
          }

        • 示例2

          package main

          //超时控制的经典实现
          import (
          "fmt"
          "time"
          )

          func main() {
          ch := make(chan int)
          timeout := make(chan int, 1)
          go func() {
          time.Sleep(time.Second)
          timeout <- 1
          }()
          select {
          case <-ch:
          fmt.Println("come to read ch!")
          case <-timeout:
          fmt.Println("come to timeout")
          }
          fmt.Print("end of code!")
          }

        • 示例3

          package main

          //超时控制的经典实现
          import (
          "fmt"
          "time"
          )

          func main() {
          ch := make(chan int)
          select {
          case <-ch:
          fmt.Println("come to read ch!")
          case <-time.After(time.Second):
          fmt.Println("come to timeout")
          }
          fmt.Print("end of code!")
          }

  • 深入Go协程编程

    • 协程与线程质的不同

      • 协程任务的业务代码主动要求切换,即主动让出执行权

      • 发生了IO,导致执行阻塞

    • 线程与协程代码对比(线程几百个就卡,协程十万个都不算多)

      • Java线程

        public class MyThread{
        public static void main(String[] args){
        new Thread(new Test_thread()).start();
        new Thread(new Test_thread2()).start()
        }
        }
        class Test_thread implements Runnable{
        public void run(){
        for(int i=0;i<100;i++){
        System.out.println("thread 1:"+i)
        }
        }
        }
        class Test_thread2 implements Runnable{
        public void run(){
        for(int i=100;i<200;i++){
        System.out.println("thread 2:+i);
        }
        }
        }

      • Go协程

        package main
        import (
        "fmt"
        // "runtime"
        "strconv"
        "time"
        )
        func main() {
        //协程1
        go func() {
        for i := 1; i < 100; i++ {
        if i == 10 {
        // runtime.Gosched() //主动要求切换CPU
        <-ch //遇到阻塞主动让出,否则一直执行下去
        }
        fmt.Println("routine 1:" + strconv.Itoa(i))
        }
        }()
        //协程2
        go func() {
        for i := 100; i < 200; i++ {
        fmt.Println("routine 2:" + strconv.Itoa(i))
        }
        }()
        time.Sleep(time.Second)
        }

GO语言JSON与MD5

Go语言的JSON
  • 使用的库

    • Go语言内置的encoding/json标准库:性能不太好

    • github.com/pquerna/ffjson/ffjson

  • json使用代码

    package main

    import (
    "encoding/json"
    "fmt"
    )

    type Student struct {
    Name string //外部要引用要首字母大写
    Age int
    }

    func main() {
    //对数组类型的json编码
    x := [5]int{1, 2, 3, 4, 5}
    s, err := json.Marshal(x)
    if err != nil {
    panic(err)
    }
    fmt.Println(string(s))
    //对map类型进行json编码
    m := make(map[string]float64)
    m["zhangsan"] = 100.4
    s2, err2 := json.Marshal(m)
    if err2 != nil {
    panic(err2)
    }
    fmt.Println(string(s2))
    //对对象进行json编码
    student := Student{"zhangsan", 26}
    s3, err3 := json.Marshal(student)
    if err3 != nil {
    panic(s3)
    }
    fmt.Println(string(s3))
    //对s3进行解码
    var s4 interface{}
    json.Unmarshal([]byte(s3), &s4)
    fmt.Printf("%v", s4)
    }

  • md5使用

    package main

    import (
    "crypto/md5"
    "fmt"
    )

    func main() {
    Md5Inst := md5.New()
    Md5Inst.Write([]byte("zhangsan"))
    Result := Md5Inst.Sum([]byte(""))
    fmt.Printf("%x\n\n", Result)
    }

GO语言HTTP

  • go语言标准库内建提供了net/http包

  • 处理http请求:使用net/http包提供的http.ListenAndServer()方法,可以在指定的地址进行监听,开启一个HTTP.服务端该方法的原型如下:func ListenAndServe(addr string,hander Handler)error

    • 该方法用于在指定的TCP网络地址addr进行监听,然后调用服务端处理程序来处理传入的链接请求.该方法有两个参数:第一个参数addr即监听地址;第二个服务表示服务端处理程序,通常为空,这意味着服务端调用http.DefaultServeMux进行处理,而服务端编写的业务逻辑处理程序http.Handle()或http.HandleFunc()默认注入http.DefaultServeMux中
  • 处理https请求

    • func ListenAndServeTLS(addr string,certFile string,keyFile string,handler Handler) error

    • http.HandleFunc()方法接受两个参数

      • 第一个参数是http请求的目标路径"/hello",该参数值可以是字符串,也可以是字符串形式的正则表达式,第二个参数指定具体的回调方法,比如helloHandler

      • 当我们的程序运行起来后,访问-http://localhost:8080/hello,程序就会去调用hellloHandler()方法中的业务逻辑程序

  • http中get和postdaima

    • //get代码
      package main

      import (
      "fmt"
      "io/ioutil"
      "net/http"
      )

      func main() {
      resp, err := http.Get("http://www.baidu.com")
      if err != nil {
      panic(err)
      }
      defer resp.Body.Close()
      body, err := ioutil.ReadAll(resp.Body)
      fmt.Println(string(body))
      }
      //post代码
      package main

      import (
      "fmt"
      "io/ioutil"
      "net/http"
      "strings"
      )

      func main() {
      resp, err := http.Post("http://www.baidu.com", "application/x-www.form-urlencoded", strings.NewReader("id=1"))
      if err != nil {
      panic(err)
      }
      defer resp.Body.Close()
      body, err := ioutil.ReadAll(resp.Body)
      fmt.Println(string(body))
      }

GO语言正则表达式

Go语言标准库内建提供了regexp包
  • 正则字母含义

    • .匹配除换行符以外的任意字符

    • \w匹配字母或数字或下划线或汉字

    • \s匹配任意的空白符

    • \d匹配数字

    • \b匹配单词的开始或结束

    • ^匹配字符串的开始

    • $匹配字符串的结束

    • *重复零次或更多次

    • +重复一次或更多次

    • ?重复零次或一次

    • {n}重复n次

    • {n,}重复n次或更多次

    • {n,m}重复n到m次

    • 捕获(exp) 匹配exp,并捕获文本到自动命名的阻组里

    • (?exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)

    • (?:exp)匹配exp,不捕获匹配的文本,也不给此分组分配组号

  • 正则函数

    • func Match(pattern string,b []byte)(matched bool,err error)

    • func MatchString(pattern string,s string)(matched bool,err error)

    • func MustCompile(str string)*Regexp

    • func(re * Regexp)FindAllString(s string,n int)[]string

  • 代码演示

    • package main

      import (
      "fmt"
      "regexp"
      )

      func main() {
      isok, _ := regexp.Match("[a-zA-Z]{3}", []byte("zhl"))
      fmt.Printf("%v", isok)
      reg1 := regexp.MustCompile(^z(.*)l

      z(.{1})(.{1})(.*)l
       result2 := reg2.FindAllStringSubmatch("zhangsan", -1)
      fmt.Printf("%v\n", result2)

      }

    • 代码演示2

      package main

      import (
      "fmt"
      "io/ioutil"
      "net/http"
      "regexp"
      )

      func main() {
      url := "https://movie.douban.com/subject/1292052/"
      resp, err := http.Get(url)
      if err != nil {
      panic(err)
      }
      defer resp.Body.Close()
      sHtml, _ := ioutil.ReadAll(resp.Body)
      // fmt.Println(string(sHtml))
      reg := regexp.MustCompile((.*))
      result := reg.FindAllStringSubmatch(string(sHtml), -1)
      // fmt.Printf("%v", result)
      // for _, v := range result {
      // fmt.Println(v[1])
      // }
      fmt.Println(result[0][1])
      reg1 := regexp.MustCompile((.*))
      result1 := reg1.FindAllStringSubmatch(string(sHtml), -1)
      fmt.Println(result1[0][1])
      }

GO语言Mysql与Redis

Go语言使用mysql驱动包:https://github.com/Go-SQL-Driver/Mysql
  • 使用sql.open()函数用来打开一个注册过的数据库驱动,Go-MySQL-Driver中注册了mysql这个数据库的驱动,第二个参数是DNS(Data Source Name),它是Go-MySQL-Driver定义的一些数据库链接和配置信息.它支持如下格式

    • user@unix(/path/to/socket)/dbname?charset=utf8

    • user:password@tcp(localhost:5555)/dbname?chaset=utf8

  • Go语言操作mysql代码

    • package main

      import (
      "database/sql"
      "fmt"

      _ "github.com/go-sql-driver/mysql"
      

      )

      func main() {
      db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/cost?charset=utf8")
      if err != nil {
      panic(err)
      }
      //插入
      // stmt, err := db.Prepare("insert test set t_id=?,t_name=?,t_time=?")
      // res, err := stmt.Exec(998, "zhangsan", "2019-01-02")
      // id, err := res.LastInsertId()
      //修改
      // stmt, err := db.Prepare("update test set t_name=? where t_id=?")
      // res, err := stmt.Exec("lisi", 999)
      // id, err := res.RowsAffected()
      //数据库一主多从,从库多是用来查询的
      //查询
      rows, err := db.Query("select * from test where t_id=999")
      if err != nil {
      panic(err)
      }
      for rows.Next() {
      var t_id int
      var t_name string
      var t_time string
      err = rows.Scan(&t_id, &t_name, &t_time)
      fmt.Println(t_id, t_name, t_time)
      }
      //在go中创建的变量必须调用一次
      // fmt.Println(id)
      }

Go语言使用的Redis驱动包:https://github.com/astaxie/goredis
  • 驱动包需设置gopath下载使用

  • 下载安装redis并启动

  • redis的基本操作类型

    • string

    • hash

    • set

    • list

    • zset

  • redis代码示例

    package main

    import (
    "fmt"

    "github.com/astaxie/goredis"
    

    )

    func main() {
    var client goredis.Client
    client.Addr = "127.0.0.1:6379"
    //存入数据到redis
    err := client.Set("test", []byte("hello beifeng"))
    if err != nil {
    panic(err)
    }
    //从redis获取数据
    res, err := client.Get("test")
    if err != nil {
    panic(err)
    }
    fmt.Println(string(res))
    //库中hmset方法使用
    f := make(map[string]interface{})
    f["name"] = "zhangsan"
    f["age"] = 12
    f["sex"] = "male"
    err = client.Hmset("test_hash", f)
    if err != nil {
    panic(err)
    }
    //库中 zset方法使用
    _, err = client.Zadd("test_zset", []byte("beifeng"), 100)
    if err != nil {
    panic(err)
    }
    }

  • redis命令行操作查看

    • //启动服务
      redis-server.exe
      //启动客户端查看数据
      E:\quickSorftWare\redis>redis-cli.exe
      127.0.0.1:6379> get test
      "hello golang"
      127.0.0.1:6379> type test_hash
      none
      127.0.0.1:6379> type test_hash
      hash
      127.0.0.1:6379> hgetall test_hash
      1. "age"
      2. "12"
      3. "sex"
      4. "male"
      5. "name"
      6. "zhangsan"
        127.0.0.1:6379> hgetall test_zadd
        (empty list or set)
        127.0.0.1:6379> type test_zadd
        none
        127.0.0.1:6379> type test_zset
        zset
        127.0.0.1:6379> zrange test_zset 0 -1
      7. "golang"

你可能感兴趣的:(Go语言入坑)