gofumpt比默认的gofmt更严格

安装gofumpt到local go workspace

export GOPATH=/home/gpadmin/go
export GOBIN=$GOPATH/bin
go get mvdan.cc/gofumpt
// Go 1.17以后,推荐go install
go install mvdan.cc/gofumpt@latest

配置gofumpt

// .vimrc,配置后适用于vim-go
let g:go_fmt_command = "gofumpt"

// coc-settings.json,适用于coc.nvim
{
  "go.formatTool": "gofumpt"
}

使用gofumpt

// 命令行,-w代表原地修改
gofumpt -w .

// vim-go
:GoFmt
或者修改后自动fmt

init本地project

go mod init my-local-project

get 指定版本的包

go get github.com/lib/pq@v1.2.0

代码中删除了某个依赖,并且想要从go.mod中清除它

go mod tidy

构建,基于go.mod里的模块版本

go build
go test

重新初始化模块,有时候需要用到,如go build总是不产生可执行程序。

rm go.mod go.sum
go mod init exec_example
go get
go build

国内设置golang proxy

[mxadmin@dw1-cn exec]$ go get github.com/lib/pq
go: module github.com/lib/pq: Get "https://proxy.golang.org/github.com/lib/pq/@v/list": dial tcp 142.251.43.17:443: i/o timeout
[mxadmin@dw1-cn exec]$ go env -w GOPROXY=https://goproxy.cn,direct
[mxadmin@dw1-cn exec]$ go get github.com/lib/pq
go: downloading github.com/lib/pq v1.10.9
go: added github.com/lib/pq v1.10.9

插件、驱动初始化
在Go中,引入一个包并使用下划线作为其别名意味着只初始化该包并调用其init()函数(如果存在),但不使用该包中的任何其他函数或变量。这通常用于那些作为驱动或插件提供的包,这些驱动或插件在被导入时需要进行一些初始化工作。

下面例子导入了github.com/lib/pq包,该包为Go的database/sql提供了PostgreSQL数据库驱动。导入此包的目的是注册该驱动,使其可以在database/sql中使用。实际上,github.com/lib/pq包的init()函数负责这项工作,所以您只需导入它,而不必在代码中显式引用它。

这种导入方式使您可以在程序中使用标准的database/sql接口与PostgreSQL数据库进行交互,而不必直接使用github.com/lib/pq提供的任何特定函数或类型。

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

引用
在Go中,切片(slice)、映射(map)和通道(channel)这三种类型的变量都是引用类型。这意味着当你将一个映射赋值给另一个变量时,实际上是将原映射的引用赋值给了新变量。因此,对新变量进行的任何修改也会影响到原映射,反之亦然。

下面例子,chState 和 session.ChState 都引用相同的底层映射数据结构,所以对其中一个进行的任何修改都会影响到另一个。

type Session struct {
    ChState      map[string] int
}

chState := session.ChState
chState[segmentID] = ChStateIdle

map的值
在 Go 中,map 中的值在访问时都会被复制。
chState 是从 session.ChState[segmentID] 获得的映射值的拷贝。因此,改变 chState 的值并不会影响 session.ChState[segmentID] 的值。

chState, exists := session.ChState[segmentID]
if exists {
    chState = Idle
}

判断map中key是否存在

if value, ok := myMap[key]; ok {
    // key exists in the map, and its value is stored in the variable 'value'
} 

命令行参数
os.Args

package main

import (
    "fmt"
    "os"
)

func main() {
    // Check the number of arguments
    if len(os.Args) < 2 {
        fmt.Println("Usage:", os.Args[0], "<param1> <param2> ...")
        return
    }

    // Print all arguments
    for i, arg := range os.Args {
        fmt.Printf("Argument %d: %s\n", i, arg)
    }
}
$ go run main.go arg1 arg2 arg3

Argument 0: /tmp/go-build/main
Argument 1: arg1
Argument 2: arg2
Argument 3: arg3

flag

package main

import (
    "flag"
    "fmt"
)

func main() {
    // Define flags
    name := flag.String("name", "Guest", "Your name")
    age := flag.Int("age", 0, "Your age")

    var country string
    flag.StringVar(&country, "country", "Unknown", "Your country")

    // Parse the flags
    flag.Parse()

    // Use the flag values
    fmt.Printf("Hello, %s! You are %d years old.\n", *name, *age)
}
$ go run main.go -name=John -age=30
Hello, John! You are 30 years old.

synchronization 相关
channels 或者WaitGroup通常更简单,能应对大多数场景。sync.Mutex更复杂但应对的场景更加广泛。

var wg sync.WaitGroup

func myGoroutine() {
    // Some setup or initialization code
    wg.Done()  // Signal that the setup is complete

    // Rest of the goroutine logic
}

func main() {
    wg.Add(1)
    go myGoroutine()

    wg.Wait()  // Wait for the goroutine to signal that it's ready

    // Continue with the main logic
}
var m sync.Mutex
var ready = false
var cond = sync.NewCond(&m)

func myGoroutine() {
    m.Lock()
    // Some setup or initialization code
    ready = true
    m.Unlock()

    cond.Broadcast()  // Signal that the setup is complete

    // Rest of the goroutine logic
}

func main() {
    go myGoroutine()

    m.Lock()
    for !ready {  // Wait for the condition to be true
        cond.Wait()
    }
    m.Unlock()

    // Continue with the main logic
}
readyChan := make(chan struct{})

func myGoroutine() {
    // Some setup or initialization code
    close(readyChan)  // Signal that the setup is complete

    // Rest of the goroutine logic
}

func main() {
    go myGoroutine()

    <-readyChan  // Wait for the goroutine to signal that it's ready

    // Continue with the main logic
}

goroutine退出行为

goroutine A启动goroutine B,A退出后,B不会退出。但是main routine退出后,所有相关的goroutine都会退出。见下面链接中的例子

https://verinumbenator.medium.com/do-go-routines-end-when-the...

package main

import (
 "fmt"
 "time"
)

func main() {

 defer println("Main Function Returned Here")

 CallingFunction()

 time.Sleep(5 * time.Second) //wait to see
}

func CallingFunction() {
 defer println("Calling Function Returned Here")

 dataCh := make(chan struct{})

// Start a goroutine that runs an infinite loop that prints a message and sleeps for 1 second in each iteration
 go func(ch chan struct{}) {
  for i := 0; ; i++ {
   fmt.Println("goroutine running: ", i)
   if i == 3 {
    ch <- struct{}{}
   }
   time.Sleep(1 * time.Second)
  }
 }(dataCh)

// Wait for a value to be received on the dataCh channel
 <-dataCh

 return

}

output:

goroutine running:  0
goroutine running:  1
goroutine running:  2
goroutine running:  3
Calling Function Returned Here
goroutine running:  4
goroutine running:  5
goroutine running:  6
goroutine running:  7
Main Function Returned Here

Program exited.

学习资料:
电子书

cheatsheet


黑暗森林
12 声望3 粉丝

弱小和无知不是生存的障碍,傲慢才是!


下一篇 »
Rust相关