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)
}