Go快速入门

一、环境安装

1、源码包下载

https://golang.org/dl/

https://golang.google.cn/dl/

https://studygolang.com/dl/

2、下载解压至/usr/local

tar -zxvf go1.14.4.linux-amd64.tar.gz -c /usr/local

3、cd /usr/local/go

src 源码

bin go指令 gofmt指令

4、配置bin到环境变量

vim ~/.bashrc

export GOROOT=/usr/local/go goRoot,表示go源码包所在位置

export GOPATH=$HOME/go goPath,写go代码的工作路径

export PATH=PATH:GOROOT/bin:$GOPATH/bin

source ~/.bashrc

5、验证

go version

二、语言特性

1、极简的部署

ldd 程序名 查看依赖关系

2、静态类型语言

编译期间能检测出隐藏的大多数问题,动态的比如shell

3、语言层面的并发

4、强大的标准库

runtime系统调度机制:用于垃圾回收,go调度的平均分配

gc垃圾回收:1.8后增加三色标记以及混合写屏障

丰富的标准库

三、语法新奇

1、main函数

Go 复制代码
package main //程序的包名,当前文件一定包含main函数

import (
    "fmt"
    "time"
)


func main(){
    fmt.Println("hello")
    time.Sleep(1*time.Second)
}

2、数据类型

Go 复制代码
//布尔型 false %t
    var isFlag bool
    fmt.Printf("%T,%t\n",isFlag,isFlag)
// 数值型 整形 0 %d
    uint8 0~255 别名byte
    uint16    rune
    uint32
    uint64
    int8 -127~128
    int16
    int32
    int64    int
    
//数值型 浮点型 0.0 %f
    默认6位小数,%.2f 保留两位小数
    float32 IEEE-754 32位浮点数
    float64 IEEE-754 64位浮点数
    complex64 32位实数和虚数
    complex128 64位实数和虚数
//字符串 string 空 %s
    双引号
    单引号会转为ASCⅡ编码表,unicode编码表,全世界文字,gbk全中国
转义字符 \

类型转换

Go 复制代码
a:=3 //int
b:=5.0 //float64
//将int类型的a转换为float64类型
c:=float64(a)

整形不能转为布尔

3、运算符

算术运算符

+、-、*、/、%、++(自增)、--

关系运算符

==、>、<、>=、<=、!=

逻辑运算符

&& 、||、!

位运算符

& 位与,都是1,结果位1

| 位或,都是0,结果为0

^ 位异或,不同为1

&^ 位清空,a&^b,对于b上数值,如果为0,则取a对应位数值,为1,取0

<< 左移,高位丢弃,低位补0,乘以2的n次方

>> 右移,地位丢弃,高位补0,除以2的n次方

4、 变量

Go 复制代码
package main

import{
    "fmt"
}

//声明全局变量 方法一二三是可以的,方法四不行
var gA int =100


func main(){
    //方法一 声明一个变量 默认是0
    var a int

    //方法二 初始化
    var b int =100

    //方法三
    var c=100

    //方法四
    d:=100
    //打印类型%T
    fmt.Printf("%T",d)



    //声明多个变量
    var xx,yy int =100,200
    var kk,ll =100,"abc"
    var(
        vv int =10
        jj bool =true
    )
}
Go 复制代码
package main
 
import "fmt"
 
func main(){
 
    // := 自动推导
    name := "zhangsan"
    var age int
    age=18
    //%T表示打印类型
    fmt.Println("%T",name)
 
    //%p 表示打印地址 
    fmt.Println("age:%d,内存地址:%p",age,&age)
 
    age=20
    //地址不会变
 
}

变量交换

Go 复制代码
package main
 
func main(){
    var a int=100
    var b int =200
    //交换a,b的值
    b,a=a,b
}

匿名变量:_ 空白标识符,任何赋给这个标识符的值将被抛弃

Go 复制代码
package main
 
import "fmt"
 
func test()(int ,int){
    return 100,200
 
}
func main(){
    a,_:=test()
    _,b:=test()
    fmt.Println(a,b)
}
//匿名变量不占用内存空间,不会分配内存

5、常量

Go 复制代码
package main

import (
    "fmt"
)


//const来定义枚举类型
const (
//可以在const()添加一个关键字iota,每行iota都累加1,第一行0
    //Beijing=0
    //Shanghai=1
    //SHENZHEN=2
    BEIJING=iota //0  如果10*iota,分别是 0,10,20
    SHANGHAI    //1
    SHENZHEN    //2
)
const(
    a,b=iota+1,iota+2    //iota=0 a=1,b=2
    c,d                  //iota=1 c:iota+1=2,d:ioata+2=3
    e,f                  //iota=2,e=3,f=4

    g,h=iota*2,iota*3    //iota=3,g=6,h=9
    i,k                  //iota=4,i=8,h=12


)

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

}

iota只有在const中使用

6、流程控制

Go 复制代码
var a int=90
 
switch a{
 
case 90:
    fmt.Println("A")
case 80:
    fmt.Println("B")
case 50,60,70:
    fmt.Println("C")
default:
    fmt.Println("D")
}
switch默认匹配成功后不会执行其他case,如果需要执行其他case,可以使用fallthrough穿透case,break结束穿透

7、String

Go 复制代码
str:="hello"
//获取长度
    len(str)
//获取指定字节
    fmt.Pirntln(str[0])//104
    fmt.Printf("%c",str[0])//h
//字符串是一个个字符拼接而成
 
 
//for range循环 循环遍历数组、切片....
for i,v :=range str{
 
    fmt.Print(i) //下标
    fmt.Printf("%c",v)//值
 
}

8、函数

Go 复制代码
package main

import (
    "fmt"

)

func fool1(a string,b int) (int,int){
    c:=100  
    d:=200  
    return c
}

func fool2(a string b int)(r1 ,r2 int){
    r1=100
    r2=200
    return

}

func main(){



}
Go 复制代码
func main(){
    sum:=getSum(1,2,3,4)
}
 
func getSum(nums...int)(int){
    sum:=0
    for i:=0;i<len(nums);i++{
        sum+=nums[i]
    }
    return sum
}
/*
注意:
    可变参数要放在列表最后
    一个函数参数列表中最多一个可变参数
*/
Go 复制代码
func main(){
    fmt.Printf("%T",f1)    //func(int int)
    var f2 func(int,int)
    f2=f1
    f2(1,2)
 
}
func f1(a,b int){}

9、值传递与引用传递

值传递:传递的是数据的副本,修改数据对原数据没影响

基础类型、array、struct...

引用传递:传递的是地址,修改数据对原数据有影响

切片:可以扩容的数据

map、chan...

10、import导包与init函数

init()函数调用早于main()函数

函数名大写表示其他包也可以调,小写其他包无法调用

11、import匿名以及别名导包方式

Go 复制代码
package main

//直接导pak1不行,需要到gopath路径下
import (
    _"Golang/demo/pak1" 
    Golang/demo/pak2"
    mylib "Golang/demo/pak3"
    ."Golang/demo/pak4"
)
//下画线表示给pak1起匿名别名,这样即使不使用pak1的方法,也不会报错
//mylib是显式别名,可以通过其调用
//加. 将当前pak4包中全部方法导入当前main包,方法可以直接使用,但容易发生歧义

func main(){

    //pak1.Pak1funcTest()
    pak2.Pak2funcTest()
    mylib.Pak3funcTest()
    Pak4funcTest()
}

12、指针

Go 复制代码
package main


import "fmt"

func swap (pa *int,pb *int){
    var temp int
    temp=*pa
    *pa=*pb
    *pb=temp
}
func main(){
    var a int=20
    
    var p * int
    p=&a
    fmt.Println(&a)
    fmt.Println(p)


    var pp **int //二级指针
    pp=&p
    fmt.Println(&p)
    fmt.Println(pp)

}

13、 defer

Go 复制代码
package main

import "fmt"

func main(){
    defer fmt.Println("main end1")
    defer fmt.Println("main end2")//压栈执行

    fmt.Println("main hello")
}

//defer相当于c++析构,函数要结束后执行
//defer与return,return先执行

return先于defer执行,defer相当于析构

14、数组

Go 复制代码
package main

func printArr(myArr [4]int){
    //长度4和10是两个不同类型的数组,只能传长度为4的

}



func main(){
    var myArr1 [10]int
    myArr2:=[10]int{1,2,3,4}
    myArr3:=[4]int{1,2,3,4}    

    for i:=0;i<len(myArr1);i++{
        fmt.Println(myArr1[i])
    }

    for idx,value:=range myArr2{
        fmt.Println(idx,value)
    }

    //值拷贝
    printArr(myArr3)
}
Go 复制代码
package main

import "fmt"
func printArr(myArr []int){

}

func main(){
    myArr:=[]int{1,2,3,4}//动态数组,切片

    //切片是引用类型,传递的是指针
    printArr(myArr)

}

15、slice(动态数组)

Go 复制代码
package main

import "fmt"


func main(){
    //声明slice是一个切片,并且初始化,默认值是1,2,3,长度3
    slice1:=[]int{1,2,3}

    //声明slice是一个切片,但是并没有分配空间,如果尝试访问元素1,会越界错误
    var slice2 []int
    //开辟空间
    slice2=make([]int,3)

    var slice3 []int=make([]int,3)

    slice4 := make([]int,3)
    
    //初始化切片slice5是数组arr的引用
    slice5:=arr[:]
    //将arr左闭右开创建一个新的切片
    slice5:=arr[startIndex:endIndex]
    slice6:=arr[startIndex:]
    slice7:=arr[:endIndex]
    
    //判断slice是否为空
    if slice1==nil{

    }
}
Go 复制代码
package main


func main(){
    //长度为3,容量为5
    var numbers=make([]int,3,5)
    fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers)


    //添加
    numbers=append(numbers,1)

    //向容量已经满的切片继续新增,go底层会默认扩容为原来cap容量


    //截取 这种截取s,s1,s2,s3底层共享内存空间
    s:=[]int{1,2,3,4,5,6} //len=6,cap=6
    //左闭右开 [0,2)
    s1:=s[0:2]//结果是1,2
    s2:=s[:3]//结果是1,2,3
    s3:=s[0:]//全部

    //如果想分开拷贝,深拷贝(拷贝一个副本)
    s4:=make([]int,3)
    copy(s4,s)
}

切片长度和容量不同,长度表示左指针至右指针的距离,容量表示左指针至底层数组末尾的距离

扩容会扩容为原来cap的两倍

16、map

Go 复制代码
package main

func main(){
    //map[k]v 
    var myMap map[string]string
    //myMap==nil

    //开辟空间
    myMap=make(map[string]string,10)
    myMap["one"]="java"
    myMap["two"]="c++"

    //满了会扩容

    //可以写容量,也可以不写
    myMap2:=make(map[int]string)
    myMap3:=map[string]string{
        "one":"go",
    }
}
Go 复制代码
package main

func printMap(myMap map[string]string){
//myMap是引用传递 slice map channal

}



func main(){
    myMap:=make(map[string]string)

    //添加
    myMap["china"]="beijing"
    myMap["usa"]="huashengdun"

    //遍历
    for k,v:=range myMap{
        

    }

    //删除
    delete(myMap,"china")    

    //修改
    myMap["usa"]="niu"

}

17、面向对象--封装

Go 复制代码
package main


//type声明一种新的数据类型myint,是int的一个别名
type myint int


//定义一个结构体,把多种基本类型组合到一起
type Book struct{
    title string
    auth string
}

func printBook1(book Book){
//值传递 传递一个副本

}

func printBook2(book *Book){
//引用传递 
    book.auth="678"
}

func main(){
    var a myint=10

    var book1 Book

    book1.title="123"
    book1.auth="456"
    fmt.Printf("%v",book1)

    printBook2(&book1)
}
Go 复制代码
package main

type Hero struct{
    Name string
    age int
}

func (this Hero) Show{
    fmt.Println("name=",this.name)
    fmt.Println("age=",this.age)
}

func main(){
    hero:=Hero{Name:"zhangsan",age:19}
    hero.show()
}
Go 复制代码
package main

//类名首字母大写,表示其他包也能访问
type Hero struct{
//类的属性首字母大写,表示该属性是对外能够访问的
    Name string
    age int
}
//方法名大写,其他包也能访问
func (this *Hero) Show{
    fmt.Println("name=",this.name)
    fmt.Println("age=",this.age)
}

func(this *Hero)GetName()string{
    return this.Name
}

func(this *Hero)SetName(name string){
    this.name=name
}
func main(){
    hero:=Hero{Name:"zhangsan",age:19}
    hero.setName("lisi")
    hero.show()
}

18、面向对象--继承

Go 复制代码
package main

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

//继承
type SuperMan struct{
    Human //SuperMan类继承了Human类的方法
    level int
}
//重写父类方法
func (this *SuperMan)Eat(){
    fmt.Println("SuperMan:Eat")
}
//子类新方法
func (this *SuperMan)Fly(){
    fmt.Println("Fly")
}
func main(){
    h:=Human{"zhangsan","female"}
    h.Eat()

    //写法1
    s:=SuperMan{
        Human{
            "lisi",
            "male"
        },
        88
    }
    s.Eat()

    //写法2
    var sm SuperMan
    sm.name="wangwu"
    sm.level=99
}

父类的类名写到子类的结构中

19、面向对象--多态

Go 复制代码
package main


//interface本质是一个指针,指向当前interface所指向的具体类型
type Animal interface{
    Sleep()
    GetColor() string //获取动物颜色
    GetType() string //获取动物种类
}

//具体的类
type Cat struct{
    color string
}
func (this *Cat)Sleep(){

}
func (this *Cat)GetColor() string{
    return this.color
}
func (this *Cat)GetType() string{
    return "Cat"
}
func main(){
    var animal Animal//接口的数据类型,父类指针
    animal=&Cat{"Green"}
    animal.Sleep()

}

基本的要素:

有一个父类(接口)

有子类,实现了父类的全部接口方法

父类的指针指向子类

20、interface

interface 通用万能类型

Go 复制代码
package main

func myFunc(arg interface{}){
    fmt.Println(arg)
    
    //interface{} 如何区分此时引用的底层数据类型是什么
    //给interface{} 提供"断言"的机制

    //判断是否是string
    value,ok:=arg.(string)
}

type Book struct{
    auth string
}

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

21、断言

Go 复制代码
package main

func main(){
    var a string
    //a中pair <static type :string,value:"abc">
    a="abc"

    //allTpe中pair <type:,value:>
    var allType interface{}
    //allTpe中pair <type:string,value:"abc">
    allType=a

    //allTpye此时可以断言成string
    str,ok:=allTpye.(string)
}
func demo1() error{
    //tty: pair<type:*os.File,value:"/dev/path"文件描述符>
   tty,err:=os.OpenFile("/dev/path",os.0_RDWR,0)
   if err!=nil{
        return err
    }

    //r: pair<type:,value:>
    var r io.Reader
    //r: pair<type:*os.File,value:"/dev/path"文件描述符>
    r=tty

    //w: pair<type:,value:>
    var w io.Writer
    //w:pair<type:*os.File,value:"/dev/path"文件描述符>
    w=r.(io.Writer)


}




type Reader interface{
    ReadBook()
}

type Writer interface{
    WriteBook()
}

type Book struct{
}

func (this *Book) ReadBook(){

}

func (this *Book) WriteBook(){

}

func demo2(){
    // b:pair<type:Book,value:Book{}地址>
    b:=&Book{}
    
    var r Reader
    // r:pair<type:Book,value:Book{}地址>
    r=b
    r.ReadBook()

    var w Writer
    //r能断言为(Writer),因为w r具体的type是一致的,Book实现了这两个接口
    w=r.(Writer)

    w.WriteBook()
}

变量的内部构造有两部分(合起来称为pair):type与value。type(类型)分为static type(静态类型)与concrete type(具体类型)。static type 例如int,string等。concrete type指interface所指向的具体数据类型

22、反射

func ValueOf (i interface{}) Value{...} 0

func TypeOf(i interface{}) Type{...} nil

Go 复制代码
package main

import(
    "reflect"
)

func reflectNum(arg interface{}){
    fmt.Println("type:",reflect.TypeOf(arg))
    fmt.Println("value:",reflect.ValueOf(arg))
}


func main(){
    var num float64=31415
    reflectNum(num)
}
Go 复制代码
package main

type User struct{
    Id int
    Name string
}

func (this User) Call(){


}

func main(){
    user:=User{1,"abc"}
    
}

func Do(input interface{}){
    //获取input的type
    inputType:=reflect.TypeOf(input)
    fmt.Println(inputType.Name())
    //获取value
    inputValue:=reflect.ValueOf(input)
    fmt.Println(inputValue)

    //通过type获取里面的字段
    /*
        1、获取interface的reflect.Type ,通过Type得到NumField,进行遍历
        2、得到每个field,数据类型
        3、通过filed有一个Interface()方法得到对应value
    */
    for i:=0;i<inputType.NumField();i++{
        field:=inputType.Field(i)
        value:=inputType.Field(i).Interface()
        
         fmt.Printf("%s %v=%v\n",field.Name,field.Type,value)
        //Id int 1
    }
    //通过type调用里面方法
    for i:=0;i<inputType.NumMethod();i++{
        m:=inputType.Method(i)
        //m.Name Call   m.Type func(main.User)
    }


}

23、结构体标签

Go 复制代码
package main

type resume struct{
    Name string `info:"name" doc:"myName"`
    Sex string `info:"sex"`
}

func findTag(str interface{}){
    t:=reflect.TypeOf(str).Elem()

    for i:=0;i<t.NumField();i++{
        tagString :=t.Field(i).Tag.Get("info")
        fmt.Println(tagString)
    }

}

func main(){
    var re resume
    findTag(&re)
}
Go 复制代码
package main

import(
    "encoding/json"

)

type Movie struct{
    Title string `json:"title"`
    Year int `json:"year"`
    Actors []string `json:"actors"`
}

func main(){
    movie:=Movie{"戏剧",2002,[]string{"李","刘"}}

    //编码的过程  结构体---->json
    jsonStr,err:=json.Marshal(movie)

    //解码 json---->结构体
    myMovie:=Movie{}
    err = json.Unmarshal(jsonStr,&myMovie)
}

四、goroutine与channel

1、goroutine

单进程操作系统的问题:

单一执行流程、计算机只能一个任务一个任务处理

进程阻塞所带来的cpu浪费时间

多进程带来的问题

多进程/线程解决了单进程/线程的阻塞问题,但是

进程/线程数量越多,切换成本越大

多进程伴随着同步竞争(锁、竞争资源冲突等)



调度器的设计策略

复用线程

work stealing机制 :如果存在空闲的本地队列,会偷取其他队列的G来执行

hand off机制:如果G1阻塞,会立即唤醒另一个线程,将G1所关联的P迁移到另一个线程来执行,G1阻塞结束,如果还要继续执行会加入其他队列中,不执行会睡眠或销毁M1

利用并行

可以利用GOMAXPROCS限定P的个数

比如p=cpu核数/2,利用一半cpu

抢占

G时间到了抢占执行

全局G队列

优先从其他队列偷,在从全局队列获取

2、创建goroutine

Go 复制代码
package main

import(
    "fmt"
    "time"
)


//子goroutine
func newTask(){
    i:=0
    for {
        i++
        fmt.Println("从goroutine:",i)
        time.Sleep(1*time.Second)
    }
}

//主goroutine
func main(){
    //创建一个go协程 去执行newTask()
    go newTask()

    //主协程退出,从协程也会退出
    i:=0
    for{
        i++
        fmt.Println("主goroutine:",i)
        time.Sleep(1*time.Second)
    }

}
Go 复制代码
package main

func main(){
    //用go创建承载一个形参为空,返回值为空的一个匿名函数
    go func(){
        defer fmt.Println("匿名函数A defer")


        func(){
            defer fmt.Println("匿名函数B defer")
            //退出当前协程
            runtime.Goexit()  
            fmt.Println("B")
        }()
        //加()表示调用此匿名函数

        fmt.Println("A")
    }()


    //保证父协程不退出
    for{
        time.Sleep(1*time.Second)
    }
}
//正常执行:B--B defer--A--A defer
//如果想退出当前子协程 runtime.Goexit()  B defer--A defer
//return会退出当前方法

3、channel

Go 复制代码
package main

func main(){
    //定义一个无缓冲的channel
    c:=make(chan int)


    go func(){
        defer fmt.Println("goroutine结束")
        fmt.Println("goroutine运行")
        //将10写入channel
        c<-10
    }()

    a:=<-c
    fmt.Println(a)
}

make (chan Type)

make (chan Type,capacity)

channel <- value 发送value到channel

<-channel 接收并丢弃

x:=<-channel 从channel中读取数据,并赋值给x

x,ok:=<-channel

当主线程先执行到读取chan,发现还没有写入,会阻塞直到xieru

当从线程先执行到写入chan,由于没有缓冲,会阻塞直到被读取

4、channel有缓冲和无缓冲同步问题

Go 复制代码
package main

func main(){
    c:=make(chan int,3)//有缓冲的channel

    //len元素的数量,cap容量
    fmt.Println(len(c),cap(c))

    go func(){
        for i:=0;i<4;i++{
            c<-i
            fmt.Println(len(c),cap(c))
        }
    
    }()

    for i:=0;i<3;i++{
        num:=<-c
    }

}

当channel已经满,再向里面写数据,就会阻塞

当channel为空,从里面取数据会阻塞

5、channel关闭

Go 复制代码
package main

func main(){
    c:=make(chan int)
    go func(){
        for i:=0;i<5;i++{
            c<-i
        }

        //close可以关闭一个channel
        close(c)
    }()

    for {
        //ok如果为true表示channel没有关闭,如果false表示channel已经关闭
        if data,ok:=<-c;ok{
            fmt.Println(data)
        }else{
            break
        }
        //如果没有close,主协程一直读,会造成主协程死锁
    }


}

channel不需要经常去关闭,当确实没有数据可发关闭

关闭channel后,无法向channel继续发送数据(引发panic)

关闭channel后,可以继续从channel接收数据(有缓冲的)

对于nil channel(没有make),无论收发都会被阻塞

6、channel和range

Go 复制代码
package main

func main(){
    c:=make(chan int)
    go func(){
        for i:=0;i<5;i++{
            c<-i
        }

        //close可以关闭一个channel
        close(c)
    }()

   for data:=range c{
        fmt.Println(data)
   }

}

7、channel和select

Go 复制代码
package main

func fibonacii(c,quit chan int){
    x,y:=1,1
    for{
        select{
            case c<-x:
                //如果c可写,该case执行
                x=y
                y=x+y
            case <-quit:
                //如果quit可读,写入才可读
                fmt.Println("quit")
                return
        }
  
    }

}

func main(){
    c:=make(chan int)
    quit:=make(chan int)
    go func(){
        for i:=0;i<5;i++{
            //读取c,写了才能读
            fmt.Println(<-c)
        }
        //读完,quit写入0
        quit <- 0
    }()

   fibonacii(c,quit)

}

单流程下一个go只能监控一个channel的状态,select可以完成监控多个channel的状态

select{

case <- chan1:

//如果chan1成功读到数据,则进行该case处理语句,否则整个select会阻塞,随机触发

case chan2 <- 1:

//如果chan2可写

default:

//如果上面都没有成功,进入default

}

五、go modules模块管理

1、Gopath工作模式的弊端

1、没有版本控制概念,go get -u github.com/aceld/zinx 无法指定下载版本

2、无法同步一致第三方版本号

3、无法指定当前项目引用的版本号

2、GoModules模式基础环境说明

2.1 命令

go mod help 查看所有指令

go mod init 生成go.mod文件

go mod download 下载go.mod文件中指明的所有依赖

go mod tidy 整理现有依赖

go mod graph 查看现有依赖结构

go mod edit 编辑go.mod文件

go mod vendor 导出项目所有依赖到vendor目录

go mod verify 校验一个模块是否被篡改

go mod why 查看为什么需要依赖某模板

2.2 环境变量

GO111MODULE

作为Go modules的开关

auto :只要项目包含了go.mod文件,启用Go modules

on:启用

off:禁用,不推荐

go env -w GO111MODULE=on

GOPROXY

项目的第三方依赖库下载地址

默认值:https://proxy.golang.org,direct

direct表示如果代理地址中找不到需要的包,从源地址下

阿里云:https://mirrors.aliyun.com/goproxy/

七牛云:https://goproxy.cn,direct

GONOPROXY

哪些不需要代理

GOSUMDB

校验拉取的第三方库是否完整,保证拉取的代码没有被篡改

设置了goproxy就不用设置

GONOSUMDB

哪些不需要校验

GOPRIVATE

哪些库是私有的,设置后表示该库不需要通过镜像拉取,不需要校验完整性

go env -w GOPROVATE="git.example.com,github.com/zinx,*.example.com"

3、GoModules初始化项目

1、开启Go Modules模块

①go env -w GO111MODULES=on

②或者设置在环境变量中export GO111MODULE=on 设置在用户启动脚本中,需要重新打开终端或者执行source ~/.bashrc

2、初始化项目:

①创建空文件夹

②创建go.mod文件,起当前项目的模块名称 go mod init moduleName

③会生成一个go.mod文件,包含

module modlesName

go 1.20.1

④编写代码

执行go run 会自动下载依赖

手动down:go get github.com/zinx

⑤go mod会添加新代码

require github.com/zinx 版本号 //indirect

⑥会生成go.sum文件

罗列当前项目直接或间接依赖所有模块版本,保证项目依赖的版本不会被篡改

3、go mod:indirect 表示间接依赖,并没有直接依赖

4、go sum:保证库是完整的

库+h1+hash:库中所有文件hash,保证库完整性

库+go.mod+h1+hash:mod文件中的hash

4、改变模块依赖关系

改变依赖版本

go mod edit -replace=旧版本=新版本

相关推荐
JSON_L10 分钟前
微信 创建小程序码-有数量限制
后端·微信·小程序
JSON_L10 分钟前
微信创建小程序码 - 数量不受限制
后端·微信·小程序
凡人的AI工具箱34 分钟前
40分钟学 Go 语言高并发:RPC服务开发实战
开发语言·后端·性能优化·rpc·golang
R6bandito_40 分钟前
Qt几何数据类型:QLine类型详解(基础向)
c语言·开发语言·c++·经验分享·qt
Mercury_@2242 分钟前
项目集成篇:springboot集成redistemple实现自定义缓存,并且可以设置过期时间
后端·缓存
杭电码农-NEO44 分钟前
【lua语言基础(四)】IO模型以及补充知识
开发语言·junit·lua
是十一月末1 小时前
Python语法之正则表达式详解以及re模块中的常用函数
开发语言·python·正则表达式
一只大侠1 小时前
计算S=1!+2!+3!+…+N!的值:JAVA
java·开发语言
一只大侠1 小时前
输入一串字符,以“?”结束。统计其中字母个数,数字个数,其它符号个数。:JAVA
java·开发语言·算法
以后不吃煲仔饭1 小时前
面试小札:线程池
java·后端·面试