Go備忘錄

Google Go 編程規範

Golang 備忘清單

該備忘單提供了幫助您使用 Golang 的基本語法和方法。

入門

package main
import "fmt"
func main() {
    fmt.Println("Hello, world!")
}

直接運行

$ go run hello.go
Hello, world!

或者在 Go repl 中嘗試一,go 命令參考

變量

var s1 string
s1 = "Learn Go!"
// 一次聲明多個變量
var b, c int = 1, 2
var d = true
// 匿名賦值
_ , e = 10, 20 

簡短聲明

s1 := "Learn Go!"        // string
b, c := 1, 2             // int
d := true                // bool

參見:基本類型

函數

package main
import "fmt"
// 程序的入口點
func main() {
  fmt.Println("Hello world!")
  say("Hello Go!")
}
func say(message string) {
  fmt.Println("You said: ", message)
}

參見:函數(Functions)

註釋

// 單行註釋
/* 這是
多行註釋 */

if 語句

if true {
  fmt.Println("Yes!")
}

參見:條件控制

Golang 基本類型

字符串 Strings

s1 := "Hello" + "World"
s2 := `A "raw" string literal
can include line breaks.`
// 輸出:10
fmt.Println(len(s1))
// 輸出:Hello
fmt.Println(string(s1[0:5]))

字符串的類型爲 字符串

數字 Numbers

num := 3             // int
num := 3.            // float64
num := 3 + 4i        // complex128
num := byte('a')     // byte (alias: uint8)
var u uint = 7       // uint (unsigned)
var p float32 = 22.7  // 32-bit float

操作符 Operators

x := 5
x++
fmt.Println("x + 4 =", x + 4)
fmt.Println("x * 4 =", x * 4) 

參見:更多操作符

布爾值 Booleans

isTrue   := true
isFalse  := false

操作符

fmt.Println(true && true)   // true 
fmt.Println(true && false)  // false
fmt.Println(true || true)   // true
fmt.Println(true || false)  // true
fmt.Println(!true)          // false

參見:更多操作符

數組 Arrays

┌────┬────┬────┬────┬─────┬─────┐
| 2  | 3  | 5  | 7  | 11  | 13  |
└────┴────┴────┴────┴─────┴─────┘
  0    1    2    3     4     5

primes := [...]int{2, 3, 5, 7, 11, 13}
fmt.Println(len(primes)) // => 6
// 輸出:[2 3 5 7 11 13]
fmt.Println(primes)
// 與 [:3] 相同,輸出:[2 3 5]
fmt.Println(primes[0:3])

var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1]) //=> Hello World
fmt.Println(a)   // => [Hello World]

2d array

var twoDimension [2][3]int
for i := 0; i < 2; i++ {
    for j := 0; j < 3; j++ {
        twoDimension[i][j] = i + j
    }
}
// => 2d:  [[0 1 2] [1 2 3]]
fmt.Println("2d: ", twoDimension)

指針(Pointers)

func main () {
  b := *getPointer()
  fmt.Println("Value is", b)
}

func getPointer () (myPointer *int) {
  a := 234
  return &a
}
//申明指針的時候,如果沒有指向某個變量,默認值爲nil
//不能直接進行操作,包括讀寫
var p *int
*p = 123      // panic   nil pointer

//而用new返回的是有默認值的指針, 爲數據類型的默認值
func main(){
  //有一塊內存存放了10,它的地址由系統自動分配,別名是a
  a := 10
  //內存存放的10變成了20
  a = 20
  var p *int
  p = &a   //或者直接寫 p := &a
  //上面的p是一個指針,通過 *p 的方式同樣可以訪問 變量a指向 的內存

  /*當你動態申請內存的時候,指針的存在意義之一就被體現出來了*/ 
  ptr := new(int)   
  //申請了一塊內存空間,沒有辦法指定別名,new()返回內存地址,用指針接收
  //此時並沒有變量能直接指向這塊內存,所以只能通過內存地址來訪問
}

參見:指針(Pointers)

切片(Slices)

s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s)
fmt.Println(s[1])
fmt.Println(len(s))
fmt.Println(s[1:3])
slice := []int{2, 3, 4}

另見:切片示例

常量(Constants)

const s string = "constant"
const Phi = 1.618
const n = 500000000
const d = 3e20 / n

常量聲明可以使用 iota常量生成器 初始化,它用於
生成一組以相似規則初始化的常量,但是不用每行都
寫一遍初始化表達式。
注意:

  1. 在一個const聲明語句中,在第一個聲明的常量所在的行,iota被置爲0,然後在每一個有常量聲明的行加一。
  2. 寫在同一行的值是相同的
const (
    a = iota
    b
    c
)
// a = 0, b = 1, c = 2

類型轉換

Go語言中不允許隱式轉換,所有類型轉換必須顯式聲明(強制轉換),而且轉換隻能發生在兩種相互兼容的類型之間。

i := 90
f := float64(i)
u := uint(i)
// 將等於字符Z
s := string(i)

如何獲取int字符串?

i := 90
// 需要導入“strconv”
s := strconv.Itoa(i)
fmt.Println(s) // Outputs: 90

Golang 字符串

字符串函數

package main
import (
        "fmt"
        s "strings"
)
func main() {
    /* 需要將字符串導入爲 s */
        fmt.Println(s.Contains("test", "e"))
    /* 內置 */
    fmt.Println(len("hello"))  // => 5
    // 輸出: 101
        fmt.Println("hello"[1])
    // 輸出: e
        fmt.Println(string("hello"[1]))
}

fmt.Printf

package main
import (
        "fmt"
        "os"
)
type point struct {
        x, y int
}
func main() {
        p := point{1, 2}
        fmt.Printf("%v\n", p)                        // => {1 2}
        fmt.Printf("%+v\n", p)                       // => {x:1 y:2}
        fmt.Printf("%#v\n", p)                       // => main.point{x:1, y:2}
        fmt.Printf("%T\n", p)                        // => main.point
        fmt.Printf("%t\n", true)                     // => TRUE
        fmt.Printf("%d\n", 123)                      // => 123
        fmt.Printf("%b\n", 14)                       // => 1110
        fmt.Printf("%c\n", 33)                       // => !
        fmt.Printf("%x\n", 456)                      // => 1c8
        fmt.Printf("%f\n", 78.9)                     // => 78.9
        fmt.Printf("%e\n", 123400000.0)              // => 1.23E+08
        fmt.Printf("%E\n", 123400000.0)              // => 1.23E+08
        fmt.Printf("%s\n", "\"string\"")             // => "string"
        fmt.Printf("%q\n", "\"string\"")             // => "\"string\""
        fmt.Printf("%x\n", "hex this")               // => 6.86578E+15
        fmt.Printf("%p\n", &p)                       // => 0xc00002c040
        fmt.Printf("|%6d|%6d|\n", 12, 345)           // => |    12|   345|
        fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)     // => |  1.20|  3.45|
        fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)   // => |1.20  |3.45  |
        fmt.Printf("|%6s|%6s|\n", "foo", "b")        // => |   foo|     b|
        fmt.Printf("|%-6s|%-6s|\n", "foo", "b")      // => |foo   |b     |
        s := fmt.Sprintf("a %s", "string")
        fmt.Println(s)
        fmt.Fprintf(os.Stderr, "an %s\n", "error")
}

另見:fmt

函數實例

實例 Result
Contains("test", "es") true
Count("test", "t") 2
HasPrefix("test", "te") true
HasSuffix("test", "st") true
Index("test", "e") 1
Join([]string{"a", "b"}, "-") a-b
Repeat("a", 5) aaaaa
Replace("foo", "o", "0", -1) f00
Replace("foo", "o", "0", 1) f0o
Split("a-b-c-d-e", "-") [a b c d e]
ToLower("TEST") test
ToUpper("test") TEST

Golang 條件控制

有條件的

a := 10
if a > 20 {
    fmt.Println(">")
} else if a < 20 {
    fmt.Println("<")
} else {
    fmt.Println("=")
}

if 中的語句

x := "hello go!"
if count := len(x); count > 0 {
    fmt.Println("Yes")
}

if _, err := doThing(); err != nil {
    fmt.Println("Uh oh")
}

Switch

x := 42.0
switch x {
  case 0:
  case 1, 2:
      fmt.Println("Multiple matches")
  case 42:   // Don't "fall through".
      fmt.Println("reached")
  case 43:
      fmt.Println("Unreached")
  default:
      fmt.Println("Optional")
}

參見:Switch

For loop

for i := 0; i <= 10; i++ {
  fmt.Println("i: ", i)
}

對於 Range 循環

nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
  sum += num
}
fmt.Println("sum:", sum)

For 循環

i := 1
for i <= 3 {
  fmt.Println(i)
  i++
}

Continue 關鍵字

for i := 0; i <= 5; i++ {
  if i % 2 == 0 {
      continue
  }
  fmt.Println(i)
}

Break 關鍵字

for {
  fmt.Println("loop")
  break
}

Golang 結構和Maps

定義

package main
import (
        "fmt"
)
type Vertex struct {
        X int
        Y int
}
func main() {
        v := Vertex{1, 2}
        v.X = 4
        fmt.Println(v.X, v.Y) // => 4 2
}

參見:結構(Structs)

字面量

v := Vertex{X: 1, Y: 2}
// Field names can be omitted
v := Vertex{1, 2}
// Y is implicit
v := Vertex{X: 1}

您還可以輸入字段名

Maps

m := make(map[string]int)
m["k1"] = 7
m["k2"] = 13
fmt.Println(m) // => map[k1:7 k2:13]
v1 := m["k1"]
fmt.Println(v1)     // => 7
fmt.Println(len(m)) // => 2
delete(m, "k2")
fmt.Println(m) // => map[k1:7]
_, prs := m["k2"]
fmt.Println(prs) // => false
n := map[string]int{"foo": 1, "bar": 2}
fmt.Println(n) // => map[bar:2 foo:1]

指向結構的指針

v := &Vertex{1, 2}
v.X = 2

Doing v.X is the same as doing (*v).X, when v is a pointer.

Golang 函數

多個參數

func plus(a int, b int) int {
    return a + b
}
func plusPlus(a, b, c int) int {
    return a + b + c
}
fmt.Println(plus(1, 2))
fmt.Println(plusPlus(1, 2, 3))

多返回值

func vals() (int, int) {
  return 3, 7
}
a, b := vals()
fmt.Println(a)    // => 3
fmt.Println(b)    // => 7

匿名函數

r1, r2 := func() (string, string) {
    x := []string{"hello", "world"}
    return x[0], x[1]
}()
// => hello world
fmt.Println(r1, r2)

命名返回值

func split(sum int) (x, y int) {
  x = sum * 4 / 9
  y = sum - x
  return
}
x, y := split(17)
fmt.Println(x)   // => 7
fmt.Println(y)   // => 10

可變參數函數

func sum(nums ...int) {
  fmt.Print(nums, " ")
  total := 0
  for _, num := range nums {
      total += num
  }
  fmt.Println(total)
}
sum(1, 2)     // => [1 2] 3
sum(1, 2, 3)  // => [1 2 3] 6
nums := []int{1, 2, 3, 4}
sum(nums...)  // => [1 2 3 4] 10
// 不定參在內存中是連續存儲的
// 不定參內部再傳遞的時候,參數也要是不定的

初始化函數

import --> const --> var --> init()

var num = setNumber()
func setNumber() int {
  return 42
}
func init() {
  num = 0
}
func main() {
  fmt.Println(num) // => 0
}

作爲值的函數

func main() {
  // 將函數賦給名稱
  add := func(a, b int) int {
      return a + b
  }
  // 使用名稱調用函數
  fmt.Println(add(3, 4)) // => 7
}

閉包

func outer() (func() int, int) {
    outer_var := 2
    inner := func() int {
        outer_var += 99
        return outer_var
    }
    inner()
    return inner, outer_var
}
inner, val := outer()
fmt.Println(val)
// => 101
fmt.Println(inner())
// => 200,這裏涉及到golang中閉包和內存逃逸的概念,inner()實際上執行了兩次,outer()中一次,fmt又一次,
//但爲什麼是200呢,編譯器不能確定outer_var在後續會不會使用,
//所以outer_var不會隨着outer()結束而釋放它的棧(Stack)空間,
//而會‘逃逸到’堆(Heap)上,那麼第二次的inner()中outer_var就會是101。

關閉 1

func scope() func() int{
  outer_var := 2
  foo := func() int {return outer_var}
  return foo
}
// Outpus: 2
fmt.Println(scope()())

Golang 包(Packages)

導入

import "fmt"
import "math/rand"

等同於

import (
  "fmt"        // 給 fmt.Println
  "math/rand"  // 給 rand.Intn
)

另見:導入

別名

import r "math/rand"

import (
    "fmt"
    r "math/rand"
)

r.Intn()

Packages

package main
// 一個內部包只能被另一個包導入
// 那是在以內部目錄的父級爲根的樹內
package internal

另見:內部包

導出名稱

// 以大寫字母開頭
func Hello () {
  ···
}

另見:導出的名稱

Golang 併發

協程

package main
import (
    "fmt"
    "time"
)
func f(from string) {
    for i := 0; i < 3; i++ {
            fmt.Println(from, ":", i)
    }
}
func main() {
    f("direct")
    go f("goroutine")
    go func(msg string) {
            fmt.Println(msg)
    }("going")
    time.Sleep(time.Second)
    fmt.Println("done")
}

參見:Goroutines, Channels

WaitGroup

package main
import (
    "fmt"
    "sync"
    "time"
)
func w(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("%d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("%d done\n", id)
}
func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
            wg.Add(1)
            go w(i, &wg)
    }
    wg.Wait()
}

參見:WaitGroup

Closing channels

ch <- 1
ch <- 2
ch <- 3
close(ch) // 關閉頻道

// 迭代通道直到關閉
for i := range ch {
  ···
}

// Closed if `ok == false`
v, ok := <- ch

參見:範圍和關閉

緩衝通道

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// 致命錯誤:
// 所有 goroutine 都處於休眠狀態 - 死鎖

參見:緩衝通道

Golang 錯誤控制

延遲函數

func main() {
  defer func() {
    fmt.Println("Done")
  }()
  fmt.Println("Working...")
}

Lambda defer

func main() {
  var d = int64(0)
  defer func(d *int64) {
    fmt.Printf("& %v Unix Sec\n", *d)
  }(&d)
  fmt.Print("Done ")
  d = time.Now().Unix()
}

defer 函數使用當前值d,除非我們使用指針在 main 末尾獲取最終值

Defer

func main() {
  defer fmt.Println("Done")
  fmt.Println("Working...")
}

參見:Defer, panic and recover

Golang 方法(Methods)

接收器

//Go語言中的方法(Method)是一種作用於特定類型變量的函數。
//這種特定類型變量叫做接收者(Receiver)。
//接收者的概念就類似於其他語言中的 this 或者 self。
//方法的定義格式如下:
func (接收者變量 接收者類型) 方法名(參數列表) (返回參數) {
    函數體
}
// 其中,
//     1.接收者變量:接收者中的參數變量名在命名時,官方建議使用接收者類型名
//的第一個小寫字母,而不是self、this之類的命名。例如,Person類型的接收者變量
// 應該命名爲 p,Connector類型的接收者變量應該命名爲c等。
//     2.接收者類型:接收者類型和參數類似,可以是指針類型和非指針類型。
//     3.方法名、參數列表、返回參數:具體格式與函數定義相同。
type Vertex struct {
  X, Y float64
}

func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
func (v Vertex) valuechange() float64 {
  v.X += 1
  return v.X
}
func (v *Vertex) pointerchange() float64 {
  v.X += 1
  return v.X
}
func main() {
  v := Vertex{1, 2}
  v.Abs()

  v = Vertex{1, 2}
  fmt.Println(v.valuechange())  // 2
  fmt.Println(v)                // {1 2}

  v = Vertex{1, 2}
  fmt.Println(v.pointerchange())// 2
  fmt.Println(v)                // {2 2}
}
//如果在方法裏修改receiver的值要對caller生效,使用 pointer receiver。

參見:Methods指針接收器

方法表達式

方法表達式相當於提供一種語法將類型方法調用顯式地轉換爲函數調用,接收者(receiver)必須顯式地傳遞進去。

func (t T) Get(){
    return t.a
}
func (t *T) Set(i int){
    t.a = i
}
//表達式`T.Get`和`(*T).Set`被稱爲方法表達式,
//需要注意的是在方法表達式中編譯器不會做自動轉換。
//值調用會自動轉換,表達式調用則不會,例如:
type Data struct{}
func (Data) TestValue () {}
func (*Data) TestPointer () {} 
//聲明一個類型變量a
var a Data= struct{}{}
//表達式調用編譯器不會進行自動轉換
Data.TestValue(a) 
//Data.TestValue(&a) 
(*Data).TestPointer (&a) 
//Data.TestPointer(&a) //type Data has no method TestPointer 
//值調用編譯器會進行自動轉換
y : = (&a).TestValue //編譯器幫助轉換a.TestValue
g : = a.TestPointer //會轉換爲(&a).TestPointer 

組合結構的方法集

內嵌字段的訪問不需要使用全路徑,只要保證命名是唯一的就可以,儘量避免同名。如果外層字段和內層字段有相同的方法,則使用簡化模式訪問外層方法會覆蓋內層的方法。

x : = X{a: 1} 
y : = Y{ 
    X : x , 
    b : 2 , 
}
z : = z { 
    Y : y , 
    c : 3 ,
}//組合結構,內嵌字段

組合結構的方法集有如下規則:

  • 若類型 T 包含匿名字段 S ,則 T 的方法集包含S的方法集
  • 若類型 T 包含匿名字段 S ,則 T 的方法集包含 S 和S方法集
  • 不管類型 T 中嵌入的匿名字段是 S 還是 S ,T 方法集總是包含 S 和 *S 方法集

Golang 接口(Interfaces)

基本接口(Interfaces)

type Shape interface {
  Area() float64
  Perimeter() float64
}

結構(Struct)

type Rectangle struct {
  Length, Width float64
}

結構 Rectangle 通過實現其所有方法隱式實現接口 Shape

方法(Methods)

func (r Rectangle) Area() float64 {
  return r.Length * r.Width
}
func (r Rectangle) Perimeter() float64 {
  return 2 * (r.Length + r.Width)
}

Shape 中定義的方法在Rectangle中實現

接口實例

func main() {
  var r Shape = Rectangle{Length: 3, Width: 4}
  fmt.Printf("Type of r: %T, Area: %v, Perimeter: %v.", r, r.Area(), r.Perimeter())
}

Golang Embed (Go version >= 1.16)

嵌入爲string

package main

import (
    _ "embed"
    "fmt"
)

//go:embed version.txt
var version string

func main() {
    fmt.Printf("version %q\n", version)
}

嵌入爲[]byte

package main
import (
    _ "embed"
    "fmt"
)

//go:embed version.txt
var versionByte []byte

func main() {
    fmt.Printf("version %q\n", string(versionByte))
}

嵌入爲embed.FS

//go:embed hello.txt
var f embed.FS
func main() {
  data, _ := f.ReadFile("hello.txt")
  fmt.Println(string(data))
}

嵌入多個文件

//go:embed hello.txt
//go:embed hello2.txt
var f embed.FS
func main() {
  data, _ := f.ReadFile("hello.txt")
  fmt.Println(string(data))
  data, _ = f.ReadFile("hello2.txt")
  fmt.Println(string(data))
}

嵌入子文件夾下的文件

//go:embed p/hello.txt p/hello2.txt
var f embed.FS
func main() {
  data, _ := f.ReadFile("p/hello.txt")
  fmt.Println(string(data))
  data, _ = f.ReadFile("p/hello2.txt")
  fmt.Println(string(data))
}

同一個文件嵌入爲多個變量

//go:embed hello.txt
var s string
//go:embed hello.txt
var s2 string
func main() {
  fmt.Println(s)
  fmt.Println(s2)
}

匹配模式

//go:embed p/*
var f embed.FS
func main() {
  data, _ := f.ReadFile("p/.hello.txt")
  fmt.Println(string(data))
  data, _ = f.ReadFile("p/q/.hi.txt") // 沒有嵌入 p/q/.hi.txt
  fmt.Println(string(data))
}

Golang 泛型 (Go version >= 1.18)

泛型類型

type S[T int|float32|float64 ] []T
       ┬  ────────┬──────── 
       ┆          ╰─── 2. 類型約束
       ╰────────────── 1. 類型形參

可以使用類型實參 int 或 string 實例化

type MyMap[K int|string, V float32 | float64] map[K]V

var a MyMap[string, float64] = map[string]float64{
    "jack_score": 9.6,
    "bob_score":  8.4,
}
  • 匿名結構體不支持泛型
  • 匿名函數不支持泛型

泛型函數

任意類型

func Add[T any](a,b T) T {
    return  a+b
}

對類型進行約束

func Add[T string | int | int8](a,b T) T {
    return  a+b
}

類型嵌套

type WowStruct[T int | float32, S []T] struct {
    Data     S
    MaxValue T
    MinValue T
}

var ws WowStruct[int, []int]  

泛型函數中進行類型聲明 (go version >= 1.20)

func F[T1 any]() {
    type x struct{} 
    type y = x      
}

泛型約束

通過接口實現

type Addable interface{
    type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string 
}

func Add[T Addable](a,b T) T {
    return  a+b
}

使用 ~ 符號

type Int interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64
}

type Uint interface {
    ~uint | ~uint8 | ~uint16 | ~uint32
}
type Float interface {
    ~float32 | ~float64
}

type Slice[T Int | Uint | Float] []T 

var s Slice[int] // 正確

type MyInt int
var s2 Slice[MyInt]  // MyInt底層類型是int,所以可以用於實例化

type MyMyInt MyInt
var s3 Slice[MyMyInt]  // 正確。MyMyInt 雖然基於 MyInt ,但底層類型也是int,所以也能用於實例化

type MyFloat32 float32  // 正確
var s4 Slice[MyFloat32]

使用 ~ 時的限制:

  1. ~後面的類型不能爲接口
  2. ~後面的類型必須爲基本類型

泛型 Receiver

定義普通類型支持泛型

type MySlice[T int | float32] []T

func (s MySlice[T]) Sum() T {
    var sum T
    for _, value := range s {
        sum += value
    }
    return sum
}

結構體支持泛型

type A[T int | float32 | float64] struct {
}

func (receiver A[T]) Add(a T, b T) T {
    return a + b
}

泛型接口

type Uint interface { // 接口 Uint 中有類型,所以是一般接口
    ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}

type ReadWriter interface {  // ReadWriter 接口既有方法也有類型,所以是一般接口
    ~string | ~[]rune

    Read(p []byte) (n int, err error)
    Write(p []byte) (n int, err error)
}

一般接口類型不能用來定義變量,只能用於泛型的類型約束中

雜項

關鍵字(Keywords)

  • 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

運算符和標點符號

+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^=

Go 命令

Go 編譯器命令

:- --
go command [參數] go 命令 [參數]
go build 編譯包和依賴包
go clean 移除對象和緩存文件
go doc 顯示包的文檔
go env 打印go的環境變量信息
go bug 報告bug
go fix 更新包使用新的api
go fmt 格式規範化代碼
go generate 通過處理資源生成go文件
go get 下載並安裝包及其依賴
go install 編譯和安裝包及其依賴
go list 列出所有包
go run 編譯和運行go程序
go test 測試
go tool 運行給定的go工具
go version 顯示go當前版本
go vet 發現代碼中可能的錯誤

ENV

:- --
GOOS 編譯系統
GOARCH 編譯arch
GO111MODULE gomod開關
GOPROXY go代理 https://goproxy.io https://goproxy.cn https://mirrors.aliyun.com/goproxy/
GOSSAFUNC 生成 SSA.html 文件,展示代碼優化的每一步 GOSSAFUNC=func_name go build

Module

:- --
go mod init 初始化當前文件夾,創建go.mod文件
go mod download 下載依賴的module到本地
go mod tidy 增加缺少的module,刪除無用的module
go mod vendor 將依賴複製到vendor下
文件 go.mod 依賴列表和版本約束
文件 go.sum 記錄 module 文件 hash 值,用於安全校驗

另見

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章