首页 > 技术文章 > GO入门学习

DengSchoo 2021-03-27 10:27 原文

Go语言环境配置(Linux下)

下载GO源代码

Google官方网站:https://golang.org/dl/

Go官方镜像:https://golang.google.cn/dl/

中文网站:https://studygolang.com/dl

安装GO源代码

tar -zxvf go.... -C /usr/local/

修改环境变量

vim ~/.bashrc

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
GOROOT表示源代码位置
GOPATH表示开发者GO的项目默认路径

source ~/.bashrc

go version检查是否安装成功

go --help检查是否安装成功

GO IDE

  • Goland
  • VScode
  • Vim + Go 插件

Golang 概览

优势

极简单的部署方式

  • 可直接编译机器码(编译速度可以超过C)
  • 不依赖其它库ldd 查看依赖
  • 直接运行即可部署(运行速度慢于C/C++)

静态类型语言

  • 编译时检查出来隐藏的大多数问题

语言层面的并发

  • 天生的并发支持
  • 充分利用多核(切换成本低 充分利用CPU)
package  main
import (
	"fmt"
    "time"
)

func goFunc(i int) {
    fmt.Printf("goroutine", i , "...")
}

func main() {
    for i:= 0; i < 10000; i++ {
        go goFunc(i) // 开启协程
    }
    time.Sleep(time.Second)
}

强大的标准库支撑

  • runtime系统调度机制
  • 高效的GC垃圾回收
  • 丰富的标准库
    • 加密解密
    • 底层库
    • email
    • 文本
    • 输入输出
    • 数学
    • 压缩
    • 测试
    • 文件系统
    • 进程、线程Goroutine
    • 数据持久化与交换
    • 网络通信
    • 同步机制
    • 应用构建
    • 数据结构与算法

简单易学

  • 25个关键字
  • C语言简洁基因,内嵌C语法支持
  • 面向对象特征(继承、多态、封装)
  • 跨平台

大厂常用

  • Google
  • facebook(facebookgo)
  • Tencent(蓝鲸)
  • Baidu(BFE, 通讯消息, 百度云盘Go版本)
  • 京东
  • 小米、七牛(原生GO公司)、阿里巴巴、bilibili、ByteDance

image-20210314202722239

image-20210314202810994

使用领域

云计算基础设计领域

  • Docker
  • K8s
  • etcd
  • consul
  • cloudflare CDN
  • 七牛云存储

基础后端软件

  • tidb
  • infuxdb
  • cockroachdb

微服务

  • go-kit
  • micro
  • monzo bank的typhon
  • bilibili
  • tarsgo

互联网基础设施

  • 以太坊
  • hyperledger

缺点(不足)

包管理

大部分包都在Github上

无泛化类型

所有Exception都用Error来处理

没有try catch

对C的降级处理,并非无缝,没有C降级到ASM那么完美(序列化问题)

兼容C代码也只是通过Cgo来调用C的代码

Go基础

从main方法来了解go的语法规则

image-20210314204009126

image-20210314204105046

package main // 当前程序属于main包
/*
import "fmt"
import "time"
*/

import (
	"fmt"
    "time"
)

// main 函数

func main() { // 花括号只能是这种代码风格
    fmt.Printf("Hello GO")
    time.Sleep(1 * time.Second)
}

编译并执行:

go run hello.go

四种变量声明方式

// 声明全局变量 1 2 3 方法可以
var gA int = 100
var gB = 200

// 第四种方法声明全局变量 只能在函数体内部声明
//gC := 200

func Var() {
	// 四种变量声明方法

	// 1. 声明一个变量 默认值是0
	var a int
	fmt.Println(a)

	// 2. 声明变量初始化
	var b int = 100
	fmt.Println(b)

	// 3. 在初始化的时候,让编译器根据值来匹配类型
	var c = 100
	fmt.Printf("type of C = %T\n", c)

	// 4. 常用的方法 省去var关键字 直接自动匹配
	e := 100
	fmt.Printf("type of e = %T\n", e)

	// 声明多个变量
	var x, y int = 100, 200
	var xx, yy = 100, "xx"

	var (
		vv int  = 100
		jj bool = true
		ss      = "aaaa"
	)
	var emptyString string
	fmt.Println(emptyString, x, y, xx, yy, vv, jj, ss)
}

常量与iota

package main

import (
	"fmt"
)

// const 定义枚举属性
const (

	// 可以在const添加关键字 iota, 每一行的iota都会累加1, 第一行默认是0
	BEIJING = 10 * iota
	SHANGHAI 
	SHENZHEN 
)
const (
	a, b = iota + 1, iota + 2 // iota = 0
	c, d // iota = 1
	e, f

	g, h = iota * 2, iota * 3
	
)

// 枚举属性

func main() {
	// 常量 只读
	const length int = 10;

}

函数多返回值

func fool(a string, b string) int {
    return 100
}
//匿名返回多个值
func fool2 (a string, b string) (int, int) {
    return 100 ,2
}]
// 返回多个值带有形参名称 默认地址为0
func fool3(a string, b int) (r1 int, r2 int) {
    r1 = 1000;
    r2 = 2000;
    return 
}
func fool4 ()(r1, r2 int) {
    r1 = 1
    r2 = 2
    return  
}

func mian() {
    c := fool ("aa", "bb")
    a , b = fool2("aa", "bb")
    ret1, ret2 = fool3("aa", 12)
    
}

Import导包路径与init方法调用

image-20210314213650071

import(
	"GolangStudy/5-inti/lib1" // 相对路径完成
)

image-20210314214136705

import匿名及别名导包

import (
	_ "GolangStudy..." // _为匿名 可能不使用
    myLib "Lib" // 别名
    . "MyLib" // MuLib包下的方法都是在本包下的
)
func main() {
    muLib.test()
    MyLibTest()
}

GO指针

package main
import "fmt"
func changeValue(p *int) {
    *p = 10
}
func main() {
    var a int = 1
    changeValue(&a)
    fmt.Println("a = ", a)
}

defer语句调用顺序

defer按照压栈的顺序来打印

func main() {
    defer fmt.Println("main end1")
    defer fmt.Println("main end2")
    defer myFunc()
}

image-20210315090112717

数组与动态数组的区别

func main() {
    var MyArray [10]int // 默认0
    var MyArray2 [10]int{1, 2, 3, 4} // 默认0
    
    for idx, value range MyArray2 {
        
    }
}
func print(myArray []int) {
    // 引用传递
    for _, value := range myArray {
        
    }
}
func main() {
    MyArray := []int {1, 2, 3, 4}// 默认0
    
}

四种slice切片声明定义方式

func main() {
    // 声明初始长度为3的
    slice1 := []int{1, 2, 3}
    
    // 声明slice是一个切片 但是没有空间
    var slice2 []int
    slice2 = make([]int, 3) // make来开辟空间
    slice2[0] = 100
    
    //1 ,2 合二为一 
    var slice3 []int = make([]int, 3)
    
    slice4 := make([]int, 3)
    
    
    fmt("%d, %v", len(slice1), slice1) // %v 打印详细信息
    
}

slice切片追加与截取

追加

func main() {
    var numbers = make([]int, 3, 5)
}

image-20210315124153701

func main() {
    var numbers = make([]int, 3, 5) // len = 3, cap = 5
    numbers = append(numbers, 1) // 追加1 len = 4, cap = 5
}

超过之后采用初始化的cap * k进行 append

func main() {
    var numbers = make([]int, 3) // len = 3 cap = 3
    numbers = append(numbers, 1) // 追加1 len = 4, cap = 6
}

截取:浅拷贝

func main() {
    numbers := []int{1, 2, 3}
    s1 := s[0 :2]
}

深拷贝

func main() {
    numbers := []int{1, 2, 3}
    s1 := make([]int, 3)
    copy(s1, numbers)
}

map三种声明方式

func main() {
    
    // 1.声明myMap为map类型 key是int value 为string
    var myMap map[int]string // 默认空map
    myMap := make(map[int]string, 10) // 开辟十个空间
    myMap[1] = "java" // hash表 所以是乱序
    myMap[222] = "c++"
    
    // 2. 第二种声明
    myMap := make(map[int]string)
    myMap[2] = "java"
    
    
    //3. 第三正声明方式
    myMap := make(map[string]string) {
        "aa" : "java"
        "sss" : "aaaa"
    }
    
}

map的使用方式

func main() {
    
    cityMap := make(map[string] string)
    
    // 插入或修改
    cityMap["china"] = "beijing"
    cityMap["Jappen"] = "Tokyo"
    //遍历
    for key, value := range cityMap {
        
    }
    
    // 删除
    delete(citMap, "china")
    
}

结构体

// typedef 
type myint int

// 结构体
type Book struct {
    title string
    auth string
    id int
    
}

func printBook(book Book) {
    // 副本传递
    fmt.Printf("%dv\n", book1)
}
func main() {
    var book1 Book
    book1.title = "Golang"
    fmt.Printf("%dv\n", book1)
    
}

面向对象与类的封装

// 类就是结构体来访问方法 类名大写表示对其它包开放 否则内部访问
type Hero struct {
    Name string
    Ad int
    level int  // 内部访问 private 
}
// this拷贝执行当前调用的对象
func (this Hero) GetName(){
    fmt.Printf("name = %s", this.name)
}
// this * 指针可以修改
func (this *Hero) SetName(name string){
    this.Name = name
}

func main() {
    hero := Hero{Name : "zhang3", ad:100, level:1}
}

面向对象继承

type Human struct {
    name string
    sex string
}
func (this *Human) Eat() {
    fmt.("Human Eat.")
}
func (this *Human) Walk() {
    fmt.("Human walk.")
}

type SuperMan struct {
    Human
    level int
}
// 覆盖、重写父类方法
func (this *superMan) Eat() {
    fmt.("Superman Eat.")
}


func main() {
    h := Human{"zhang3", "female"}
    h.Eat()
    h.walk()
    
    s := SuperMan{
        Human{"li4", "femal"}
        levle : 1
    }
    s.Walk() // 父类的方法
    s.Eat() // 子类的方法
    
    var s SuperMan
    s.name = "li4"
    s.sex = "male"
    s.level = 88
    
}

多态的实现及基本要素

// 本质是一个指针 可以指向实现该接口的任意类
type Animal interface {
    Sleep()
    GetColor() string
    GetType() string
}

type Cat struct { 
    color string
}
func (this *Cat) Sleep() {
    fmt.Printl("Cat is Sleep")
}
func (this *Cat) GetColor() string{
    return this.color
}
func (this *Cat) GetType() {
    return "Cat"
}

type Dog struct { 
    color string
}
func (this *Dog) Sleep() {
    fmt.Printl("Cat is Sleep")
}
func (this *Dog) GetColor() string{
    return this.color
}
func (this *Dog) GetType() {
    return "Cat"
}

func ShowAnimal(animal AnimalIF) {
    animal.Sleep() // 多态实现
}

func main() {
    var animal AnimalIF // 接口数据类型 指针
    animal = &Cat{"Green"}
    animal.Sleep() 
}

空接口万能类型与类型断言机制

func myFunc(arg interface {}) {
    fmt.Printf("myFunc")
    fmt.Println(arg)
    
    // 区分底层数据类型 -- 类型断言
    value,ok = arg.(string) // 判断是否是string
    if !ok {
       // not string
    } else {
       // is string
    }
    
}

func main() {
    book := Book{"golang"}
    myFunc(book)
    myFunc(123)
}

内置pair结构

image-20210315221157027

image-20210315221622665

image-20210315221937266

反射机制reflect包

ValueOf 返回pair中的value

TypeOf返回pair中的type

import(
	"reflect"
)
// 基本用法
func reflectNum(arg interface{}) {
    fmt.Println("type:", reflect.TypeOf(arg))
    fmt.Println("type:", reflect.ValueOf(arg))
}

image-20210315222900937

结构体标签

package main
type resume struct {
    // 说明作用 有什么作用
    Name string `info:"anme" doc:"我的名字"`
    Sex string `info:"sex"`
}
func findTag(str interface{}) {
    t := reflec.TypeOf(str)
    for i := 0; i < t.NumFiled() {
        tag := t.Filed(i).Tag.Get("info")
        fmt.Printf(tag)
    }
}

func main() {
    
}

结构体标签在json中的应用

import "encoding/json"
type Movie struct {
    Title string `json:"title"` // 标签映射
    Year int	`json:year`
    Price int	`json:rmb`
    Actors []string `son:actors`
}

func main() {
    movie := Movie{"喜剧之王", 200, 10, []string{"xingye", "zhangbozhi"}}
    // 编码过程:结构体 -> json
    jsonStr, err := json.Marshal(movie)
    if err != nil {
        return
    }
    fmt.Println(jsonStr);
    
    // 解码过程 jsonStr -> 结构体
    myMovie := Movie{}
    err = json.Unmarshal(jsonStr, &myMovie)
    if err != nil {
       	return 
    }
    
}

创建goroutine

// 子goroutine
func newTask() {
    i := 0
    for {
        i ++
        fmt.Printf("new Goroutine")
        time.Sleep(1 * time.Second)
    }
}

// 主goroutine
func main() {
    go newTask
    i := 0
    
    for {
        i++
        fmt.Printf("new Goroutine")
        time.Sleep(1 * time.Second)
    }
}

匿名函数

// 子goroutine


// 主goroutine
func main() {
    go func() {
        
    }
}

image-20210316182744344

拿不到goroutine的返回值

Channel

image-20210316183149650

无缓冲channel

image-20210316183602928

有缓冲的channel

image-20210316183704473

当通道被填满(或者为空)的时候就会阻塞掉。

image-20210316183855913

channel的关闭特点

image-20210316184337449

  • 关闭后不能再发送,但是可以继续接收
  • nil channel 无论收发都要被阻塞

channel与range

image-20210316184924796

迭代查询c的range

channel与select

image-20210316185059458

image-20210316185233033

select 具备监听多路channel的监控状态

GoModules

GOPATH工作模式的弊端

  • 没有版本控制概念
  • 无法同步一致第三方版本号
  • 无法指定当前项目引用的第三方版本号

image-20210320120502215

image-20210320120720208

GoModules初始化项目

  • 开启go模式

    go env -w GO111MODULE=on

  • 创建新项目路径:新建任意文件夹

  • go mod 初始化工作

    go mod init github.com/DengSchoo/module_test

  • 下载依赖的包

    go get github.com/

image-20210320122511560

image-20210320122540522

改变项目模块的版本依赖关系

image-20210320123121562

项目一《Golang即时通讯系统》

架构图

image-20210320123227785

版本迭代

  • 版本一:构建基础Server
  • 版本二:用户上线功能
  • 版本三:用户消息广播机制
  • 版本四:用户业务层封装
  • 版本五:在线用户查询
  • 版本六:修改用户名
  • 版本七:超时强踢功能
  • 版本八:私聊功能
  • 版本九:客户端实现

生态拓展及未来成长

web框架

beego

gin

echo

Iris

微服务框架

go kit

Istio

容器编排

K8s

swarm

服务发现&注册

consul

存储引擎

kv存储:etcd

分布式存储:tidb

静态建站

hugo

中间件

消息队列:nsq

Tcp长链接框架(轻量级服务器):zinx

Leaf(游戏服务器)

RPC框架 gRPC

Redis集群:codis

爬虫框架

go query

推荐阅读