Go to learn
This article is based on the go learning video on Bilibili. Golang Engineer (if you want to learn Go at a low cost)
Define the package
The main package in the current file is the main function. The main package is independent of the file name
Package main // Package nameCopy the code
Guide package
import "fmt"
Copy the code
Importing multiple packages
import(
"fmt"
"time"
)
Copy the code
Note: an error will be reported if the package is not used after the guide
Anonymous guide package
You don’t use it after you guide the package but you can execute the init function in the package.
import _ "packageName"
Copy the code
Note: The underscore (_) indicates anonymity. This syntax can also define anonymous variables
Don’t auteur package
Call a method in an import package by (alias. Method name)
import lib1 "packageName"
Copy the code
Import all the methods in the package (try not to use them)
Import all methods in the package into the current class, no need (package name). Method name).
import . "package"
Copy the code
The main function
Basic function, invisible parameter, no return value
func main(){ fmt.Println("hello go"); // The semicolon can be added or not.Copy the code
Curly bracket problem
The go language requires that the opening curly brace in a function must be on the same line as the function name
func main(){
}
Copy the code
Eg: error
func main()
{
}
Copy the code
syntax error:unexpected semicolon or newline before {
The program compiled
go build hello.go
Copy the code
Program execution
./hello
Copy the code
Compile + execute
go run hello.go
Copy the code
There are four ways to declare variables
Methods a
Declare a variable
var a int
var a string
Copy the code
At this point, no initialization value is given. The default value is 0
Way 2
Declare a variable and give its initial value
var b int = 100
var b string = "abcd"
Copy the code
Methods three
Initialization omits the variable’s data type and matches the current variable’s data type with the given value
var c = 100
var c = "abcd"
Copy the code
Methods four
The most commonly used – omits the var keyword directly and automatically matches. Risk implies that both declaration and assignment types are automatically derived by risk
e:100
Copy the code
Note: method 4 cannot declare global variables := can only be declared inside functions
Print out the data type of the variable
fmt.Printf("type of c = %T\n",c)
Copy the code
Declare multiple variables
The same type
Var aa,bb int = 100,200Copy the code
Different types of
var cc,dd = 100,"dd"
Copy the code
Multiline multivariable declarations
var(
ee int = 100
ff bool = true
)
Copy the code
constant
The use of constants (constant – only readable, not reassigned or modified) simply requires that var be written as const. eg:
const width int = 100
Copy the code
Constants define enumerated types
const(
BEIJING=0
SHANGHAI=1
GUANGZHOU=2
SHENZHEN=3
)
Copy the code
Iota increment is used in constant
Regular use
We can add the keyword iota to const(). Each ioTA increments by 1. The ioTA on the first line defaults to 0. The effect of ioTA autoincrement reduces our manual assignment.
Const (BEIJING =iota // iota defaults to 0 BEIJING = 0 SHANGHAI // SHANGHAI=iota increment by 1 GUANGZHOU = iota = 2 SHENZHENCopy the code
Add operations when assigning
In addition, when one of the above constants is assigned by IOTA, the rules following the equal sign of the constant are the following rules for the assignment of the following constants. The only difference is that the following constants get the value after ioTA increases by 1 eg:
Const (BEIJING = 10*iota // BEIJING = 0 SHANGHAI = 10*iota // BEIJING = 0 SHANGHAI = 0 So SHANGHAI = 10 GUANGZHOU // now the rule is 10*iota because the iota value of the first row is 2, so GUANGZHOU = 20 SHENZHEN now the rule is 10*iota because the iota value of the first row is 3, So SHENZHEN = 30)Copy the code
Modify the rule after adding a few lines
const( a,b=iota+1,iota+2 //iota = 0 ,a = iota + 1,b = iota + 2,a=1,b=2 c,d //iota = 1 ,c = iota + 1,d = iota + 2,c=1,d=2 e,f //iota = 2 ,e = iota + 1,f = iota + 2,e=1,f=2 g,h=iota*2,iota*3 //iota = 3 ,g = iota * 2,h = iota * 3,g=6,h=9 i,k //iota = 4 ,g = iota * 2,h = iota * 3,g=8,h=12 )Copy the code
Iota can only be used with const()
function
The uppercase letter of the function name indicates that the function is open to the outside world and can be called by other packages. Lowercase letters indicate that the function can only be called by other packages inside the wallet. Uppercase function names can also be understood as common methods of a class.
The basic function
func add(a int,b int) int{
return a+b
}
Copy the code
use
Func main(){sum := add(1,2)}Copy the code
The function returns multiple values
Return multiple return values (anonymous)
Fun muitReturn(a int,b string)(int,int){return 666,777}Copy the code
use
fun main(){
aaa,bbb:=muitReturn(111,"ssss")
}
Copy the code
Return multiple return values (with parameter names)
Returns a value with the parameter name, or defaults to 0 if the method body does not assign a value to it.
Fun muitReturn(a int,b string)(r1 int, R2 int){r1=100 r2=200 return}Copy the code
Return multiple return values (with parameter names and return values of the same type)
Fun muitReturn(a int,b string)(r1, R2 int){r1=100 r2=200 return}Copy the code
Guide packet problem and init method call
Execute logic as file method
1- Main package file 2- Constants 3- Variables 4-init function 5-main function 6- Exit
Let’s label this logic A
Contains the package method execution logic
If there are other packages imported in the main package, the program performs logical recursion to import subpackages and initialize constants -> initialize variables -> execute init function -> return to the previous file to initialize constants -> initialize variables -> execute init function -> return to the previous file to execute until the main method is finished. End of the program
Pointer to the
When we pass a value, after changing the value in changeVal, a is still 1, we just pass the value of a, 1, into the function. Nothing in the function changes the specific value of the external variable A.
Package main import "FMT" func changeVal(b int){b = 10} func main(){a:=1 changeValue(a) fmt.print("a = "+a }Copy the code
Pass a pointer
package main import "fmt" func changeVal(b *int){ *b = 10 } func main(){ a:=1 changeValue(&a) fmt.print("a = "+a) // a is 1}Copy the code
A pointer to level 1 can be found by jumping 1 down.
*a
Copy the code
The second level pointer finds the value by jumping 2 (a has a pointer to another address).
**a
Copy the code
defer
Defer to use
Defer can be followed by any expression or function.
Defer execution order
Defer takes the form of a pushback and is executed at the back of the stack after the current function that uses defer has been executed. Eg:
func main(){
defer fmt.Println("defer 1");
defer fmt.Println("defer 2");
fmt.Println("defer 3");
fmt.Println("defer 4");
}
Copy the code
The output
defer 3
defer 4
defer 2
defer 1
Copy the code
Legend:
The order of defer and return
When return and defer appear in the same function, the return will be called first and the defer logic will be called after the last curly brace, so the return logic will be called before the defer logic.
An array of
To define an array
- Define an array of type int with length 10
var arr[10]int
Copy the code
- Define an array with initial values, 10 in length and several default values
The arr: [10] = int {1, 2, 3, 4}Copy the code
- Viewing array types
Printf("arr type = T% \n",arr) // Print [4]intCopy the code
Through the array
- Normal traversal
for i=0; i<len(arr); i++{ }Copy the code
- Traversal with subscripts
for index,value:range arr{ fmt.Println(“index = “,index,”value = “,value) }
Array is the argument to the method
Array When the argument, the length of the array in the argument, then the length of the array passed when this function is called has to be what it is. Otherwise, a type mismatch error is reported.
func bianLi([4]int){
}
Copy the code
Array when method arguments — is value copy
Arrays are value copies when used as method arguments. The contents of the external source array do not change, although the value of the array is changed in the method.
MyArray :=[4]int{11,22,33,44} func add(arr [4]int){arr[0]=111} ftt. Print(arr[0]Copy the code
Dynamic array (slice)
You don’t specify the number of elements in the array
Creating a dynamic array
Create a dynamic array and assign an initial value
Arr: int [] = {1, 2, 3, 4}Copy the code
Dynamic array as function argument
Dynamic array When a function argument does not specify the number of elements in the array
func asum(arr []int){
}
Copy the code
Dynamic arrays are traversed in the same way as arrays
Dynamic arrays are passed by reference
MyArray :=[]int{11,22,33,44} func add(arr []int){arr[0]=111} ftt. Print(arr[0])//Copy the code
Four ways to declare slices
- Declare slice1 to be a slice and initialize it, default is 123, length len is 3
Slice: int [] = {1, 2, 3}Copy the code
- An error is reported when you declare slice but do not allocate space for slice
var slice []int
Copy the code
To create space
Slice = make([]int,3)// type []int, length 3Copy the code
- Declare slice to be a slice that allocates three Spaces at the same time, initialized to 0
var slice []int = make([]int,3)
Copy the code
- Slice := declare slice to be a slice that allocates three Spaces at the same time, initialized to 0
slice:make([]int,3)
Copy the code
Slice to empty
slice == nil
Copy the code
Section addition and interception
Obtaining slice length
len(slice)
Copy the code
Obtaining slice capacity
cap(slice)
Copy the code
Section definition
The following definition means that its capacity is 5 and its length is 3
Var number = make (int [], 3, 5)Copy the code
Slice additional
numbers=append(numbers,1)
Copy the code
After executing this method, the size of numbers is still 5, but len has changed to 4.
Add an element to a slice whose capacity is already full, and the system will dynamically open up the space of the slice's original capacity
Slice the interception
Intercept the first two elements [0,2]
S: int [] = {1, 2, 3} s1: = s [2-0]Copy the code
Intercept from scratch (included in index 0) to a position (not included in index 2).
s1:=s[:2]
Copy the code
Truncated to the end of index 2
s1:=s[2:]
Copy the code
Note: The source slice will also change after the element value changes in the new slice after slice interception. That is, the address of the original slice and the intercepted slice element are the same
Slice the copy
The above slice interception gives us a partial reference to the original slice. If we want to directly copy the elements of a slice completely, changing the new slice without affecting the old one, we need to use the copy function.
s2 := make([]int,3)
copy(s,s2)
Copy the code
In this case, S2 is a completely different address space. Changing the elements in S2 does not affect the values in S.
map
The map’s statement
Declare myMap to be a map type where key is string and value is string. The map is empty.
var myMap map[string]string
Copy the code
Map Allocates data space
- Allocate data space and set the initial capacity 10
myMap = make(map[string]string,10)
Copy the code
- Allocate data space without setting capacity
myMap = make(map[int]stirng)
Copy the code
- Declare and initialize
MyMap: map [string] string = {" zhangsan ":" male "and" lisi ":" male ",}Copy the code
The use of the map
1, add
MyMap :=make(map[string]string) myMap[" Beijing "]=" Beijing "myMap[" Shanghai "]=" Shanghai" myMap[" Shanghai "]=" Shanghai "myMap[" Shanghai "]=" Shanghai"Copy the code
2, traverse
for key,value := range myMap{
fmt.Println("key")
fmt.Println("value")
}
Copy the code
3, delete,
delect(myMap,"beijing")
Copy the code
4, modify,
myMap["beijing"]="china"
Copy the code
5. Map parameter passing (reference passing) Map variables are passed into a method as parameters, after the variable value is changed inside the method. The values stored in the external map also change accordingly
Func changeValue(cityMap map[string]string){cityMap[" Beijing "]=" Shanghai "} // The value of the external cityMap has also changedCopy the code
Struct basic definition and use
Use the type keyword to define a new type
TypeInt is an alias for int
Type typeInt int var a typeInt = 10Copy the code
Define a structure
type Book struct{
bookName string
price int
}
Copy the code
Use a structure
1. Structure declaration
var myBook Book
Copy the code
2. Use of structure
Mybook.bookname = "8 hours to learn go "mybook.price = 0Copy the code
3, structure printing % V can print any type
fmt.print("%v \n",myBook)
Copy the code
4. Structure as function parameters
Value pass, what you pass into the function is a copy of the structure, and if you change the value of the structure inside the function, the value of the outside doesn't change
Func changeBook(book book){// Pass a copy of book}Copy the code
The pointer
Func changeBook(book * book){// A pointer to book is passed in.Copy the code
The representation of a class
1, preparation: a structure
Type Human struct{// The first letter of a property in uppercase indicates that the property is accessible externally, otherwise only internally. name string age int sex string }Copy the code
2, Bind method to structure (value copy)
func (this Human) getName() string{ fmt.Println("this name = ") return this.name } func (this Human) setName(newName String){// is a copy of the object on which the method was called, without changing the value stored in the edge object. this.name=newName }Copy the code
3, Bind method to structure (pass by reference)
// The method starts with a capital letter, which you can access in other modules and other packages. Func (this *Human) GetName() string{fmt.println ("this name = ") return this.name} // The first letter of the method is lowercase, which means that you cannot access it in other modules and other packages. Func (this *Human) setName(newName string){// Is a copy of the object on which the method was called, without changing the value stored in the edge object. this.name=newName }Copy the code
The above two steps, defining a structure + defining a method and binding it to a structure, make up the concept of a class in the ordinary sense
Object creation
1. Create an object
Hero: the Human = {name: "zhangsan", the age: 10, sex: "male"}Copy the code
2. Call the method
Hero.getname () hero.setName(" hero.setName ")Copy the code
Class inheritance
1, the parent class
type Human strct{
name string
sex string
}
func (this *Human) eat(){
fmt.Println("human eat()")
}
Copy the code
Create a child structure that inherits the Human class
Type SuperMan struct{Human //SuperMan class inherit Human class age int}Copy the code
3, redefine the parent class method
func (this *SuperMan) eat(){
fmt.Println("super fly")
}
Copy the code
Define new methods for subclasses
func (this *SuperMan) fly(){
fmt.Println("SuperMain flying")
}
Copy the code
Define a subclass object
The first way
SuperMan := superMan {Human{" superMan "," male "},88} superMan:= superMan {Human{" superMan "," male "},88} superMan.Copy the code
The second way
var superMan SuperMan
Copy the code
Interface + polymorphism
Define an interface
An interface is essentially a pointer
type Animal interface{
Sleep()
GetColor() string
GetType() string
}
Copy the code
2, interface subclass implementation
To implement an interface, all the methods in the interface are implemented in a class.
Type Cat struct{color string type string// type} func (this *Cat) Sleep(){fmt.println (" Cat is sleeping ")} func (this *Cat) GetColor() string{ return this.color } func (this *Cat) GetType() string{ return this.type }Copy the code
3. Pass the object of the subclass to the declaration of the interface
Func main(){var animal animal = &cat ("red"," three flower ")// animal.sleep ()// call CatCopy the code
Method defines interface parameters and passes subclass objects when used
func showAnimal(animal Animal){
animal.Sleep()
}
Copy the code
call
ShowAnimal (& Cat (" red ", "three flowers"))Copy the code
Empty interfaces (universal types) and interface assertion mechanisms
Int, string, float32 float64, struct implements the empty interface. So you can reference any data type with an empty interface type
Empty interface
1. Empty interface writing method
interface{}
Copy the code
2. Use the empty interface as a parameter
// Interface {} is a universal data type, so this method can pass any parameter func SetName(name interface{}){}Copy the code
3, use the above method (can pass any type)
Var cat= cat {"red"," three flowers "} setName(cat) setName("name") setName(100) setName(3.14)Copy the code
Assertion mechanism
Intface {} how to determine what the underlying data type is?
Mechanism for type assertion of interface{}.
value,ok :=arg.(string) if ! ok{ fmt.Println("arg is not a string type") }else{ fmt.Println("arg is a string type value=",value) fmt.Println("value type is %T \n",value) }Copy the code
The existence of a pair in a variable
Structure of variables
The basic structure of variables in Golang consists of two parts: 1, Type 2 and value. Type can be divided into static type and concrete type. See below:
1. Pair description
var a string
//pair<type,value>
a="abcdefg"
Copy the code
In fact, there’s going to be a pair<type,value> inside of a in which case the type would be string, and the value would be “abcdefg” and the string would be string in which case the type would be staticType
2. No matter who I assign a to, the pair stays the same
Var allType interface{} //allType is pair<type,value> allType=aCopy the code
Type assertion
str,_:=allType.(string)
fmt.Println(str)
Copy the code
reflection
The Reflect package provides a reflection mechanism that allows us to retrieve type and value information from unknown variables
1. Return value of any type
func ValueOf(i interface{}) Value{
}
Copy the code
Return any type of type
func TypeOf(i interface{}) Type{
}
Copy the code
Reflect a base type
func reflectNum(arg intface{}){ fmt.Println("type = ",reflect.TypeOf(arg)) fmt.Println("value = ",reflect.ValueOf(arg)) } func main(){var num float64=1.2345 reflectNum(num)}Copy the code
Reflect a class
1. Define a base class
type User struct{ Name string Id long Age int } func (this *User) Call(){ fmt.Println("user is called") } func main(){ User := user {" user ",1000001,21}}Copy the code
Get the type and value of the class
TypeOf(user) fmt.Println("inputType is",inputType) // Obtain value inputValue:=inflect.ValueOf(user) fmt.Println("inputValue is",inputValue)Copy the code
3. Use type to get the fields inside
//1. Get the interface inflact.Type and use Type to get numberField. Value for I :=0; value for I :=0; i<inputType.NumField(); I ++ {field:= inputType.field (I) value:= inputValue.field (I).interface () // Print field name, field type, field value fmt.printf ("%s: %v = %v \n",field.Name,field.Type,value) }Copy the code
A printout
Name:string = "zhangsan" Id:long = 1000001 Age:int = 21Copy the code
4. Get the method call from type
for i:=0; i<inputType.NumMethod(); i++{ m := inputType.Method(i) fmt.Printf(%s: %v \n",m.Name,m.Type) }Copy the code
A printout
Call: func(main.User)
Copy the code
Structural label
The structure tag is used to explain the properties of the current structure and determine how they should be used in the package when it is imported by another package. It takes the form of key:value. Multiple pairs of key:value eg:
Name string 'info:" Name "doc:" my Name"' sex string 'info:"sex"'}Copy the code
Parse structure tags by reflection
Func findTag(STR interface{}){t:= reflict.typeof (STR).elem () for I :=0; i<t; i++{ tagInfo := t.Field(i).Tag().Get("info") tagDoc := t.Field(i).Tag().Get("doc") fmt.Println("info:",tagInfo," doc: ",tagDoc) } }Copy the code
Print the result
Info: name doc: My name info: sex doc:Copy the code
Application of structure tags in JSON
1. Prepare
import( "encoding/json" ) type Movie struc{ Title string `json:"title"` Year int `json:"year"` Price int `json:price` [] String {"xingye","zhangbozhi","zhangbozhi"," movie ":= movie {"xingye","zhangbozhi"}Copy the code
2. Structure –> JSON
jsonStr:err := json.Marshal(movie) if err! =nil { fmt.Println("json marshal err",err) return }else{ fmt.Printf("jsonStr = %s \n",jsonStr) }Copy the code
3. The json – > structure
myMovie:=Movie{} err := json.Unmarshal(jsonStr,$myMovie) if err ! = nil{ fmt.Println("unmashal json err",err) return } fmt.Println("%v \n",myMovie)Copy the code
Go coroutine (Goroutine)
Creation of coroutines
Func newTask(){I := 0 for{I ++ fmt.println("new goroutine: I = %d \n", I) time.sleep(1* time.second)}} func main(){// Create a go coroutine to execute newTask().Copy the code
All slave coroutines are dependent on the main coroutine, and the remaining slave coroutines exit automatically if the main method exits.
Create a no-parameter GO coroutine using the go keyword
func main(){
go func(){
defer fmt.Pintln("A.defer")
func(){
defer fmt.Println("B.defer")
fmt.Println("B")
}
fmt.Println("A")
}
}
Copy the code
Create a parameter and call
Go func(a int,b int) sum{var sum int = a+b ftt. Println("a+b=",sum) return sum}(10,20Copy the code
Exit the current GO program
- Nested layer 1
If only one layer is nested, exit with returnCopy the code
- Nested layers
runtime.Goexit()
Copy the code
Channel is used to communicate between GO coroutines
Legend:
1. Definition of channel
Make (chan Type) // Make (chan Type,capacity)// Capacity Specifies the cache capacity.Copy the code
2. Simple communication
Channel < -channel // receive and discard value x := < -channel // Receive and assign value to x x, ok := < -channel // same function as above, Also check whether the channel is closed or emptyCopy the code
3. Basic use of channel
Func main(){define a channel c:=make(chan int) go func(){defer fmt.println ("goroutine finished ") fmt.println ("goroutine running ") c < -666 // Write 666 to channel}() num := < c // accept data from C and give num fmt.println ("num value is ",num) FMt.println ("main gorotine ends...") )}Copy the code
Print the result
The Gorotine runtime in the Goroutine ending num value is 666 main Gorotine ending...Copy the code
4. Why main in case 3 always ends after the subcoroutine ends
The channel itself has the ability to synchronize two GO coroutines. In this case, two coroutines (main and subcoroutines) are executed asynchronously at the same time (both may be executed to the desired statement). When num:= < -c is executed in the main coroutine, if no data is returned in the channel, The main coroutine, the main method, is going to block here, waiting for the subcoroutine to execute to c < -666 and put 666 into a channel. The main coroutine then performs the normal operation of fetching data from the channel and assigning num. Then print out the num value
Unbuffered channel
- Step 1: Both coroutines arrive at the channel, but neither has started sending or receiving
- Step 2: The one on the left reaches into the channel, which simulates sending data to the channel. Then the coroutine will be locked in the channel
- Step 3: The right hand puts his coroutine into the channel, which simulates receiving data from the channel. This coroutine will also be locked in the channel until the exchange is complete
- Step 4 + Step 5: Make the swap
- Step 6: Both coroutines pull their handles out of the channel, simulating the release of the locked coroutine. Both coroutines can go and do other things
Buffered channels
- Step 1: The coroutine on the right is receiving a value from the channel
- Step 2: The right coroutine receives the value independently, while the left coroutine is sending a new value into the channel
- Step 3: The left coroutine is still sending a value to the channel, while the right coroutine is receiving another value from the channel. The two operations in this step are neither synchronous nor blocking each other.
- Step 4: Finally, all the sending and receiving is complete, and there are still a few values in the channel, and some space for more values
Note:
-
If the left side is full, it will block. Wait for the right to pick it up
-
Channel empty, right can not fetch, block, waiting for left to save
Gets the number and capacity of elements in the current channel
C :=make(chan int,3) FMT.Println(" len=", "cap=",cap(c))Copy the code
Shut down the channel
close(channel)
Copy the code
Gets a value from a channel and determines whether the current channel is closed
if value,ok := <- c ; Ok {fmt.println (value)}else{fmt.println ("channel closed)}Copy the code
- Unlike files, channels don’t need to be closed very often. They should be closed only if you really don’t have any data to send, or if you want to display the end of the range loop, etc
- After a channel is closed, data cannot be sent to the channel again, causing a Panic error. Causes the receive to return immediately
zero
value - After you close a channel, you can continue receiving data from it
- For nilChannel, both sending and receiving are blocked
The channel and the range
The normal writing of waiting for data from a channel
for{ if data , ok := <- channel; ok{ fmt.Println("data=",data) }else{ break } }Copy the code
Logic that waits for data from a channel using range shorthand
for data := range c{
fmt.Println(data)
}
Copy the code
Indicates an attempt to read a result from C, assign it to data if it returns, and go into the method body to print, or block and wait for the result if there is no data in range
The channel and the select
In a single flow, a GO can monitor only one channel status, and SELECT can monitor multiple channel status
select{ case <- chanl: Case chan2 < -1 // If chan1 succeeds in writing data to chan2, case chan2 < -1Copy the code
This section describes the GO Mod basic environment
- To use the gomod mode, ensure that the GO version is later than 1.11.0. There was no such model before 11. This module mainly depends on the go Module download verification configuration and other content.
Run the go version command
Go mod command
You can view the commands in the following table by running the go mod help command
The command | role |
---|---|
go mod init | Initialize a new Module in the current folder |
go mod download | Download the Module to the local cache |
go mod tudy | Add or remove unused modules |
go mod graph | Print the graph required by the Module |
go mod edit | Edit the go.mod file from a tool or script |
go mod vendor | Export all project dependencies to the vendor directory |
go mod verify | Verifies whether a module has been tampered with |
go mod why | Why do I need to rely on a module |
Enable the Go mod module
go env -w GO111MODULE=on
Copy the code
Create the Go module agent
Set to a domestic address, easy to download dependencies. At present there are Ali Yun and Seven Niuyun
go env -w GOPROXY=https://xxx.xxxx
Copy the code
- Ali cloud
https://mirrors.aliyun.com/goproxy/
- Seven NiuYun
https://goproxy.cn, a mirror image of directdirect said if the agent warehouse not to source lot to pull on it
GOSUMDB
Verification depends on whether the verification site has been tampered with. If the mirror proxy is set, the address of the mirror is used by default.
Disable verification (not recommended)
go env -w GOSUMDB=off
Copy the code
The Go Mod environment variable is a configuration similar to GOPROXY above.
Go mod initializes the project
You can create projects without the GOPATH directory
// Create a folder in a non-gopath directory and open the terminal. Run the following command: go mod init github.com/zhou/modules_test //init The name of the package guide is determinedCopy the code
Download the dependent
go mod get
Copy the code
Go mod depends on the specified version
Go mod edit-replace = Original version = new versionCopy the code