Go code
Contents
Go 代码片段
go goroutines pool
package main
import (
"fmt"
"github.com/sourcegraph/conc/pool"
)
func main() {
p := pool.New().WithMaxGoroutines(3)
for i := 1; i <= 5; i++ {
p.Go(func() {
fmt.Println(i)
})
}
p.Wait()
}
带ctx 的go goroutines pool
package main
import (
"context"
"errors"
"fmt"
"github.com/sourcegraph/conc/pool"
)
func main() {
p := pool.New().
WithMaxGoroutines(4).
WithContext(context.Background()).
WithCancelOnError()
for i := 0; i < 3; i++ {
i := i
p.Go(func(ctx context.Context) error {
if i == 2 {
return errors.New("I will cancel all other tasks!")
}
<-ctx.Done()
return nil
})
}
err := p.Wait()
fmt.Println(err)
// Output:
// I will cancel all other tasks!
}
channel
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 3)
// wg := conc.NewWaitGroup()
go func() {
for i := 0; i < 1000; i++ {
ch <- i
}
close(ch)
}()
// wg.Wait()
for v := range ch {
fmt.Println(v)
}
}
package main
import (
"fmt"
"github.com/sourcegraph/conc"
)
func main() {
ch := make(chan int)
// ch2 := make(chan bool)
wg := conc.NewWaitGroup()
wg.Go(func() {
for i := 0; i < 100; i++ {
ch <- i
}
close(ch)
})
for sub := range ch {
fmt.Println(sub)
}
}
复杂结构体slice排序
type Person struct {
Name string
Age int
Book int
}
people := []Person{
{"Alice", 30, 5},
{"Bob", 25, 2},
{"Charlie", 30, 55},
{"David", 25, 33},
}
// 使用 sort.Slice 进行排序,按年龄升序排列,年龄相同则按book排序
sort.Slice(people, func(i, j int) bool {
if people[i].Age == people[j].Age {
return people[i].Book < people[j].Book
}
return people[i].Age < people[j].Age
})
errorgroup
package main
import (
"errors"
"fmt"
"golang.org/x/sync/errgroup"
)
func main() {
eg := errgroup.Group{}
eg.Go(func() error {
fmt.Println("go1")
return nil
})
eg.Go(func() error {
fmt.Println("go2")
err := errors.New("go2 err")
return err
})
err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}
// 带ctx
func main1() {
eg, ctx := errgroup.WithContext(context.Background())
eg.Go(func() error {
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
fmt.Println("go1 cancel, err = ", ctx.Err())
default:
fmt.Println("go1 run")
}
return nil
})
eg.Go(func() error {
err := errors.New("go2 err")
return err
})
err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}
// 限制并发数
func main2() {
eg := errgroup.Group{}
eg.SetLimit(2)
eg.TryGo(func() error {
fmt.Println("go1 run")
return nil
})
eg.TryGo(func() error {
err := errors.New("go2 err")
return err
})
eg.TryGo(func() error {
fmt.Println("go3 run")
return nil
})
err := eg.Wait()
if err != nil {
fmt.Println("err =", err)
}
}
gorm clause
err = pa.WithContext(ctx).Clauses(
clause.OnConflict{
Columns: []clause.Column{
{Name: user.Code.ColumnName().String()},
},
TargetWhere: clause.Where{
Exprs: []clause.Expression{
clause.Expr{
SQL: "deleted_at = 0",
},
},
},
DoUpdates: clause.AssignmentColumns(cols),
},
).
CreateInBatches(items, 30)
// 表设计优化,这样只有当deleted_at为null的时候,才会触发code的唯一性校验
// create unique index pa_code
// on pa (code) where deleted_at is null;
recover 使用
func main3() {
defer func() {
if err2 := recover(); err2 != nil {
fmt.Printf("Run panic error: %v", err2)
}
}()
fmt.Println("xxx")
}
func 作为传参
package main
import "fmt"
func apply(x int, y int, f func(int, int) int) int {
return f(x, y)
}
func sum(a int, b int) int {
return a + b
}
func main() {
asum := apply(5, 10, sum)
fmt.Println(asum)
}
//
func sayHello(name string) func() string {
return func() string {
return "Hello, " + name
}
}
func main2() {
hello := sayHello("Go")
fmt.Println(hello()) // 输出: Hello, Go
}
单元测试
package main
import (
"testing"
)
func TestInit(t *testing.T) {
t.Log("heh")
helper := PersonHelper{}
helper.init("pleuvoir")
t.Log(helper.Name)
}
函数运行时间
func TimeSince(f func()) string {
start := time.Now() // 获取当前时间
f() // 执行传入的函数
// 获取结束的时间
elapsed := time.Since(start)
str := fmt.Sprintf("该函数执行完成耗时:%v", elapsed)
return str
}
func main() {
result := TimeSince(timeTest)
fmt.Println(result)
}
func timeTest() {
// 运行的函数
sum := 0
for i := 0; i < 1111111111; i++ {
sum++
}
}
随机数
//start 10,end 20,将获得这之间的随机数
func RandomSum(start int, end int) int {
// 以当前时间戳作为种子,确保每次生成的随机数都不同
rand.Seed(time.Now().Unix())
// 生成一个指定范围之间的随机整数
randomInt := rand.Intn(end-start+1) + start
return randomInt
}
生成随机字符串
const (
letterBytes = "abcdefghijklmnopqrstuvwxyz"
capitalBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
numberBytes = "0123456789"
symbolBytes = "!@#$%^&*()"
)
func RandStringBytes(n int, randomString string) string {
rand.Seed(time.Now().Unix())
b := make([]byte, n)
for i := range b {
b[i] = randomString[rand.Intn(len(randomString))]
}
return string(b)
}
func main() {
//传入随机字符串的长度,以及需要随机那些字符串
randomString := RandStringBytes(10, letterBytes+numberBytes)
fmt.Println(randomString)
}
url 解析
func main() {
// 要解析的 URL 字符串
urlString := "https://www.example.com/path/to/resource?key1=value1&key2=value2#fragment"
// 解析 URL 字符串
parsedUrl, err := url.Parse(urlString)
if err != nil {
panic(err)
}
// 输出解析后的 URL 的各个部分
fmt.Println("Scheme:", parsedUrl.Scheme)
fmt.Println("Host:", parsedUrl.Host)
fmt.Println("Path:", parsedUrl.Path)
fmt.Println("RawQuery:", parsedUrl.RawQuery)
fmt.Println("Fragment:", parsedUrl.Fragment)
// 解析 URL 的查询参数
query := parsedUrl.Query()
fmt.Println("key1:", query.Get("key1"))
fmt.Println("key2:", query.Get("key2"))
}
执行系统命令
// RunCMD 标准正确错误输出到标准正确输出
func RunCMD(str string, workDir ...string) (string, error) {
cmd := exec.Command("/bin/bash", "-c", str)
if len(workDir) > 0 {
cmd.Dir = workDir[0]
}
result, err := cmd.CombinedOutput()
if err != nil {
return string(result), err
}
return string(result), nil
}
web 文件服务
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
http.ListenAndServe(":8082", nil)
}
排序
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
}
// 排序
sort.Slice(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
// 按多个字段排序,先年龄后name
sort.Slice(people, func(i, j int) bool {
if people[i].Age == people[j].Age {
return people[i].Name < people[j].Name
}
return people[i].Age < people[j].Age
})
// 保持相同元素的原始顺序
sort.SliceStable(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
// slices.SortFunc 排序
slices.SortFunc(people, func(a, b Person) int {
if a.Age != b.Age {
return a.Age - b.Age
}
if a.Name < b.Name {
return -1
}
if a.Name > b.Name {
return 1
}
return 0
})
// 按另一个list排序
// SortByOrder 根据 orderList 的顺序对 data 进行排序。
// keyFn 用于从元素中提取用于匹配的键。
func SortByOrder[T any, K comparable](
data []T,
orderList []K,
keyFn func(T) K,
) {
// 构建顺序映射表
orderMap := make(map[K]int, len(orderList))
for i, v := range orderList {
orderMap[v] = i
}
// 排序
sort.SliceStable(data, func(i, j int) bool {
ki := keyFn(data[i])
kj := keyFn(data[j])
oi, okI := orderMap[ki]
oj, okJ := orderMap[kj]
switch {
case okI && okJ:
return oi < oj
case okI:
return true
case okJ:
return false
default:
return false // 保持原始顺序(稳定排序)
}
})
}
data := []int{5, 3, 1, 4, 2}
order := []int{3, 1, 2}
SortByOrder(data, order, func(v int) int {
return v
})
package utils
import "slices"
func SortByOrderFunc[T any, K comparable](
data []T,
orderList []K,
keyFn func(T) K,
) {
orderMap := make(map[K]int, len(orderList))
for i, v := range orderList {
orderMap[v] = i
}
slices.SortStableFunc(data, func(a, b T) int {
ka := keyFn(a)
kb := keyFn(b)
oa, okA := orderMap[ka]
ob, okB := orderMap[kb]
switch {
case okA && okB:
return oa - ob
case okA:
return -1
case okB:
return 1
default:
return 0
}
})
}
list 生成map
type abc struct {
A string
}
aa := []*abc{}
lo.KeyBy(aa, func(item *abc) string {
return item.A
})
list 生成map,value为list
// 生成 map map[string][]*abc{}
lo.GroupBy(aa, func(item *abc) string {
return item.A
})
根据条件过滤list
even := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {
return x%2 == 0
})
// []int{2, 4}
for 循环
lo.ForEach([]string{"hello", "world"}, func(x string, _ int) {
fmt.Println(x)
})
统计list里某个元素个数
count := lo.Count([]int{1, 5, 1}, 1)
// 2
统计满足条件的元素个数
count := lo.CountBy([]int{1, 5, 1}, func(i int) bool {
return i < 4
})
统计元素个数,生成map
lo.CountValues([]int{1, 2})
// map[int]int{1: 1, 2: 1}
获取map的key
// 获取map的key
keys := lo.Keys(map[string]int{"foo": 1, "bar": 2})
// []string{"foo", "bar"}
// 获取多个map的key的唯一值,组成唯一的slice
keys := lo.UniqKeys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"baz": 3})
// []string{"foo", "bar", "baz"}
获取map的value
// 获取map的值
values := lo.Values(map[string]int{"foo": 1, "bar": 2})
// []int{1, 2}
// 获取map的值并去重
values := lo.UniqValues(map[string]int{"foo": 1, "bar": 2})
// []int{1, 2}
list 转换
// 切片类型转换
lo.Map([]int64{1, 2, 3, 4}, func(x int64, index int) string {
return strconv.FormatInt(x, 10)
})
list交集
lo.Intersect([]int64{1, 2, 3, 4},[]int64{1, 2, 6, 4})
list差集
left, right := lo.Difference([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6})
// []int{1, 3, 4, 5}, []int{6}
并集
union := lo.Union([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}, []int{0, 10})
// []int{0, 1, 2, 3, 4, 5, 10}
try语法
// 基本用法
ok := lo.Try(func() error {
return nil
})
// true
json转字符串
func Marshal(data any) (str string) {
bt, _ := json.Marshal(data)
return string(bt)
}
func MarshalIndent(data any) (str string) {
bt, _ := json.MarshalIndent(data, "", " ")
return string(bt)
}
多选参数
package main
import "fmt"
type DataBaseConfig struct {
IP string
Port string
Db int
UserName string
PassWord string
}
const (
PassWord = "asd@123"
UserName = "test"
Db = 1
)
type DatabaseOptions func(*DataBaseConfig)
// 添加数据库DB
func WithDb(db int) DatabaseOptions {
return func(con *DataBaseConfig) {
con.Db = db
}
}
// 添加用户名和密码
func WithUserNamePassWord(userName, passWord string) DatabaseOptions {
return func(con *DataBaseConfig) {
con.UserName = userName
con.PassWord = passWord
}
}
// 可以设置默认参数
func DefaultDatabaseConfig(con *DataBaseConfig) *DataBaseConfig {
con.PassWord = PassWord
con.UserName = UserName
con.Db = Db
return con
}
func NewDataBaseConnect(IP, Port string, options ...DatabaseOptions) *DataBaseConfig {
// 本初始化方案,要自己填IP,其他参数可填可不填,也可以使用默认参数
con := &DataBaseConfig{
IP: IP,
Port: Port,
}
// 默认值的设定
con = DefaultDatabaseConfig(con)
// 遍历可选参数,然后分别调用匿名函数,将连接对象指针传入,进行修改
for _, op := range options {
// 遍历调用函数,进行数据修改
op(con)
}
return con
}
func main() {
// 传入自定义参数测试可选参数的输入
var options = []DatabaseOptions{
WithDb(2),
WithUserNamePassWord("hello", "passWord"),
}
con1 := NewDataBaseConnect("127.0.0.1", "27017", options...)
fmt.Printf("%#v", con1)
// 不输入可选参数的测试
con := NewDataBaseConnect("127.0.0.1", "27017")
fmt.Printf("%#v", con)
}
接口
package main
import "fmt"
// 定义接口
type Speaker interface {
Speak() string
}
// 定义结构体并实现接口方法
type Person struct {
Name string
}
func (p Person) Speak() string {
return "Hello, my name is " + p.Name
}
type Dog struct{}
func (d Dog) Speak() string {
return "Woof!"
}
// 使用接口类型的变量
func saySomething(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
person := Person{Name: "John"}
dog := Dog{}
saySomething(person)
saySomething(dog)
}
并发安全map
package main
import (
"fmt"
"sync"
)
// 进程阻塞
func main() {
var m sync.Map
m.Store("userId", 1001)
m.Store("vvvv", "hello")
val, ok := m.Load("userId")
if ok {
fmt.Println(val)
}
}
生成tree
func BuildTreePtr[T any, K comparable](
list []T,
getID func(*T) K,
getParentID func(*T) K,
getChildren func(*T) []*T,
setChildren func(*T, []*T),
rootID K,
) []*T {
nodeMap := make(map[K]*T)
var result []*T
// 1. 建立 map
for i := range list {
node := &list[i]
nodeMap[getID(node)] = node
}
// 2. 构建树
for _, node := range nodeMap {
pid := getParentID(node)
if pid == rootID {
result = append(result, node)
} else {
if parent, ok := nodeMap[pid]; ok {
currentChildren := getChildren(parent)
setChildren(parent, append(currentChildren, node))
}
}
}
return result
}
// tree验证代码
type Category struct {
ID int
ParentID int
Name string
Children []*Category
}
func main() {
list := []Category{
{ID: 1, ParentID: 0, Name: "根"},
{ID: 2, ParentID: 1, Name: "A"},
{ID: 3, ParentID: 1, Name: "B"},
{ID: 4, ParentID: 2, Name: "A-1"},
}
tree := BuildTreePtr(
list,
func(c *Category) int { return c.ID },
func(c *Category) int { return c.ParentID },
func(c *Category) []*Category { return c.Children },
func(c *Category, children []*Category) { c.Children = children },
0,
)
println(tree)
}
带深度版树
func BuildTreePtrWithDepth[T any, K comparable](
list []T,
getID func(*T) K,
getParentID func(*T) K,
getChildren func(*T) []*T,
setChildren func(*T, []*T),
rootID K,
maxDepth int,
) []*T {
nodeMap := make(map[K]*T)
depthMap := make(map[K]int)
var result []*T
// 1. 建立 map
for i := range list {
node := &list[i]
nodeMap[getID(node)] = node
}
// 2. 构建树
for _, node := range nodeMap {
pid := getParentID(node)
if pid == rootID {
result = append(result, node)
depthMap[getID(node)] = 0
} else {
if parent, ok := nodeMap[pid]; ok {
parentDepth, hasDepth := depthMap[getID(parent)]
if hasDepth && parentDepth < maxDepth-1 {
currentChildren := getChildren(parent)
setChildren(parent, append(currentChildren, node))
depthMap[getID(node)] = parentDepth + 1
}
}
}
}
return result
}
slog 日志封装
package main
import (
"log/slog"
"os"
"path/filepath"
)
func main() {
logLevel := "info"
klog := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
AddSource: true,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.SourceKey {
source := a.Value.Any().(*slog.Source)
source.File = filepath.Base(source.File)
return slog.Attr{Key: a.Key, Value: a.Value}
}
return a
},
Level: func() slog.Level {
switch logLevel {
case "debug":
return slog.LevelDebug
case "info":
return slog.LevelInfo
case "warn":
return slog.LevelWarn
case "error":
return slog.LevelError
default:
return slog.LevelInfo
}
}(),
}))
klog.Error("Error log")
klog.Warn("Warn log")
klog.Info("Hello, World!")
klog.Debug("Debug log")
}