util

package util

import (
	"bytes"
	"strconv"
	"strings"
	"sync"
)

var (
	bfPool = sync.Pool{
		New: func() interface{} {
			return bytes.NewBuffer([]byte{})
		},
	}
)

/**
 * @Description: []int64数据,用sep拼接 --> string
 * @param sep byte: 拼接符号 ','  ';'
 */
func JoinInt64s(is []int64, sep byte) string {
	if len(is) == 0 {
		return ""
	}
	if len(is) == 1 {
		return strconv.FormatInt(is[0], 10)
	}
	buf := bfPool.Get().(*bytes.Buffer)
	for _, i := range is {
		buf.WriteString(strconv.FormatInt(i, 10))
		buf.WriteByte(sep)
	}
	if buf.Len() > 0 {
		buf.Truncate(buf.Len() - 1)
	}
	s := buf.String()
	buf.Reset()
	bfPool.Put(buf)
	return s
}

// SplitInts split string into int64 slice.
/**
 * @Description: 字符串s,用符号seq切割 --> []int64
 * @param sep string: 切割符号
 */
func SplitInt64s(s string, sep string) ([]int64, error) {
	if s == "" {
		return nil, nil
	}
	sArr := strings.Split(s, sep)
	res := make([]int64, 0, len(sArr))
	for _, sc := range sArr {
		i, err := strconv.ParseInt(sc, 10, 64)
		if err != nil {
			return nil, err
		}
		res = append(res, i)
	}
	return res, nil
}
package util

// SplitString 数组分组, 用于批量查询场景
func SplitString(slice []string, size int64) [][]string {
	ret := make([][]string, 0, len(slice)/int(size)+1)
	single := make([]string, 0, size)
	for idx, num := range slice {
		single = append(single, num)
		if len(single) >= int(size) || idx+1 >= len(slice) {
			ret = append(ret, single)
			single = make([]string, 0, size)
		}
	}
	return ret
}

// SplitInt 数组分组, 用于批量查询场景
func SplitInt(slice []int, size int64) [][]int {
	ret := make([][]int, 0, len(slice)/int(size)+1)
	single := make([]int, 0, size)
	for idx, num := range slice {
		single = append(single, num)
		if len(single) >= int(size) || idx+1 >= len(slice) {
			ret = append(ret, single)
			single = make([]int, 0, size)
		}
	}
	return ret
}

// SplitInt64 数组分组, 用于批量查询场景
func SplitInt64(slice []int64, size int64) [][]int64 {
	ret := make([][]int64, 0, len(slice)/int(size)+1)
	single := make([]int64, 0, size)
	for idx, num := range slice {
		single = append(single, num)
		if len(single) >= int(size) || idx+1 >= len(slice) {
			ret = append(ret, single)
			single = make([]int64, 0, size)
		}
	}
	return ret
}

// SplitUInt32 数组分组, 用于批量查询场景
func SplitUInt32(slice []uint32, size int64) [][]uint32 {
	ret := make([][]uint32, 0, len(slice)/int(size)+1)
	single := make([]uint32, 0, size)
	for idx, num := range slice {
		single = append(single, num)
		if len(single) >= int(size) || idx+1 >= len(slice) {
			ret = append(ret, single)
			single = make([]uint32, 0, size)
		}
	}
	return ret
}

// RemoveFromStrings 移除slice指定元素
func RemoveFromStrings(slice []string, r string) {
	idx := 0
	for ; idx < len(slice); idx++ {
		if slice[idx] == r {
			slice = append(slice[:idx], slice[idx+1:]...)
			return
		}
	}
}

常用逻辑

package main

import (
	"GoRedis/pkg/errgroup"
	"GoRedis/pkg/str"
	"context"
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// chapter-1: 构造函数,"有选择"的初始化成员变量
type sexType int

const (
	sexTypeMan sexType = iota + 1
	sexTypeWoman
)

type Student struct {
	Uin  int
	Name string
	Age  int
	Sex  sexType
}

/**
 * @Description: 构造函数,"有选择"的初始化成员属性
 * @param fs ...func(*Student):
 * @return *Student:
 */
func NewStudent(fs ...func(*Student)) *Student {
	stu := &Student{}
	for _, f := range fs {
		f(stu)
	}
	return stu
}

func WithName(name string) func(*Student) {
	return func(s *Student) {
		s.Name = name
	}
}
func WithAge(age int) func(*Student) {
	return func(s *Student) {
		s.Age = age
	}
}

func WithSex(sex sexType) func(*Student) {
	return func(s *Student) {
		s.Sex = sex
	}
}

func test() {
	stu1 := NewStudent()
	stu2 := NewStudent(WithName("Jack"))
	stu3 := NewStudent(
		WithName("Jack"),
		WithAge(18),
		WithSex(sexTypeMan),
	)

	//&{ 0 0}
	fmt.Println(stu1)
	//&{Jack 0 0}
	fmt.Println(stu2)
	//&{Jack 18 1}
	fmt.Println(stu3)
}

// chapter-2: 理解interface,抽象画怎么看:https://www.bilibili.com/video/BV17K4y1k72d?spm_id_from=333.999.0.0

type BaseNum struct {
	num1 int
	num2 int
}

// 子类1: 继承
type AddNum struct {
	BaseNum
}

func NewAddNum(baseNum BaseNum) *AddNum {
	return &AddNum{BaseNum: baseNum}
}

func (a *AddNum) opt() int {
	return a.num1 + a.num2
}

// 子类2: 继承
type SubNum struct {
	BaseNum
}

func NewSubNum(baseNum BaseNum) *SubNum {
	return &SubNum{BaseNum: baseNum}
}

func (s *SubNum) opt() int {
	return s.num1 - s.num2
}

// 多态
type opter interface {
	opt() int
}

/**
 * @Description: 多态接口
 * @param o opter: 子类的实例对象
 */
func runOpt(o opter) int {
	return o.opt()
}

// 使用方式1
func test1() {
	// 父类的指针
	var op opter

	// 多态: 父类的指针,指向子类的对象,调用interface中的函数
	op = NewAddNum(BaseNum{1, 2})
	addRes := op.opt()
	fmt.Println(addRes)

	// 多态: 父类的指针,指向子类的对象,调用interface中的函数
	op = NewSubNum(BaseNum{1, 2})
	subRes := op.opt()
	fmt.Println(subRes)

}

// 使用方式2
func test2() {
	fmt.Println(runOpt(NewAddNum(BaseNum{1, 2})))
	fmt.Println(runOpt(NewSubNum(BaseNum{1, 2})))
}

// chapter-3: 控制协程数量

/**
 * @Description: 限制协程运行数量
 * @param maxRoutineNums int: 最大协程数量
 */
func testJob(maxRoutineNums int) {
	pool := make(chan struct{}, maxRoutineNums)
	wg := sync.WaitGroup{}
	for i := 1; i <= 10; i++ {
		pool <- struct{}{} // 到达上线后,阻塞
		wg.Add(1)
		go func(index int) {
			defer wg.Done()
			job(index)
			<-pool
		}(i)
	}
	wg.Wait()
}

func job(index int) { // 工作函数
	time.Sleep(time.Millisecond * 500)
	fmt.Printf("%d\n", index)
}

// 优胜劣汰: 开多个协程执行相同的任务,一个执行完,就直接返回
func work() int {
	rand.Seed(time.Now().Unix())
	randInt := rand.Intn(10) // 生成0-10之间的随机数
	time.Sleep(time.Second * time.Duration(randInt))
	return randInt
}

func testCompete(routineNums int) {
	pool := make(chan int, routineNums)
	for i := 0; i < routineNums; i++ {
		go func(index int) {
			pool <- work()
		}(i)
	}
	fmt.Println("最快用了", <-pool, "秒")
}

/**
 * @Description: (使用场景) 逐个
 */
func IterFillStudent(uins []int) ([]*Student, error) {

	if len(uins) == 0 {
		return nil, nil
	}

	const (
		routineNum = 5
	)

	ans := make([]*Student, len(uins))

	eg := errgroup.WithContext(context.Background())
	eg.GOMAXPROCS(routineNum)

	// 一个个处理,获取每个uin的信息很慢: 开协程处理
	for i := range uins {
		func(index int) {
			// 初始化
			ans[index] = &Student{}
			// 协程: 获取信息
			eg.Go(func(_ context.Context) error {
				ans[index].Uin = uins[index]
				return nil
			})
			// 协程: 获取信息
			eg.Go(func(_ context.Context) error {
				ans[index].Name = fmt.Sprintf("stu_%d", index)
				return nil
			})
			// 协程: 获取信息
			eg.Go(func(_ context.Context) error {
				ans[index].Age = index + 1
				return nil
			})
			// 协程: 获取信息
			eg.Go(func(_ context.Context) error {
				ans[index].Sex = sexTypeMan
				return nil
			})
		}(i)
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}

	return ans, nil
}

func test_iter_fill_student() {
	res, err := IterFillStudent([]int{1, 2, 3, 4})
	if err != nil {
		panic(err)
	}

	//&{Uin:1 Name:stu_0 Age:1 Sex:1}
	//&{Uin:2 Name:stu_1 Age:2 Sex:1}
	//&{Uin:3 Name:stu_2 Age:3 Sex:1}
	//&{Uin:4 Name:stu_3 Age:4 Sex:1}
	for _, v := range res {
		fmt.Printf("%+v\n", v)
	}
}

// 批量获取
func smallBatchFillStudent(uins []int) (map[int]*Student, error) {
	ans := make(map[int]*Student, len(uins))

	for _, uin := range uins {
		ans[uin] = &Student{Uin: uin}
	}

	return ans, nil
}

func BatchFillStudent(uins []int) (map[int]*Student, error) {

	const (
		routineNums = 10
		batchSize   = 1
	)

	eg := errgroup.WithContext(context.Background())
	eg.GOMAXPROCS(routineNums)

	batchUinsList := str.SplitInt(uins, batchSize)

	batchAnsChan := make(chan map[int]*Student, len(batchUinsList))

	for _, batchUins := range batchUinsList {
		tmpBatchUins := batchUins
		eg.Go(func(_ context.Context) error {
			stuList, err := smallBatchFillStudent(tmpBatchUins)
			if err != nil {
				return err
			}
			batchAnsChan <- stuList
			return nil
		})
	}
	eg.Wait()
	close(batchAnsChan)

	ans := make(map[int]*Student, len(uins))
	for v := range batchAnsChan {
		for key, value := range v {
			ans[key] = value
		}
	}

	return ans, nil
}
func main() {
	//test_iter_fill_student()
	uins := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	for {
		ans, _ := BatchFillStudent(uins)
		for k, v := range ans {
			fmt.Printf("%+v --> %+v\n", k, v)
		}
	}
}

flag库

package main

import (
	"flag"
	"fmt"
	"time"
)

const (
	timeYmdFormat = "2006-01-02 03:04:05"
)

var (
	_varA = flag.String("varA", "默认值", "变量A")
	_varB = flag.Int("varB", 0, "变量B")
	_varC = flag.Bool("varC", false, "变量C")
	_ts   = flag.String("ts", "2021-01-01 00:00:00", "开始时间")
	_te   = flag.String("te", time.Now().Format(timeYmdFormat), "结束时间")
)

func varA() string {
	return *_varA
}

func varB() int {
	return *_varB
}
func varC() bool {
	return *_varC
}

func ts() time.Time {
	t, _ := time.ParseInLocation(timeYmdFormat, *_ts, time.Local)
	return t
}

func te() time.Time {
	t, _ := time.ParseInLocation(timeYmdFormat, *_te, time.Local)
	return t
}

// ./main -varA="aaa" -varB=100 -varC=true -ts="2021-12-01 00:00:00" "2022-10-11 12:00:00"
// 输出结果:
// aaa
// 100
// true
// 2021-12-01 00:00:00 +0800 CST
// 2022-04-07 02:06:42 +0800 CST

func main() {
	flag.Parse()

	a := varA()
	b := varB()
	c := varC()

	ts := ts()
	te := te()

	fmt.Println("输出结果:")
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(ts)
	fmt.Println(te)
}