当前位置: 首页 > 工具软件 > Go Glow > 使用案例 >

Go语言入坑

常元章
2023-12-01

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$`)
      	result1 := reg1.FindAllString("zhangsan", -1)
      	fmt.Printf("%v\n", result1)
      	reg2 := regexp.MustCompile(`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(`<span\s*property="v:itemreviewed">(.*)</span>`)
      	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(`<strong\s*class="ll\s*rating_num"\s*property="v:average">(.*)</strong>`)
      	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
      1) "golang"
      
      

 类似资料: