0

Go 常用案例

 2 years ago
source link: https://zsmhub.github.io/post/golang/%E5%B8%B8%E7%94%A8%E6%A1%88%E4%BE%8B/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

golang中判断两个slice是否相等

package main

import (
    "bytes"
    "fmt"
)

func main() {
    a := []byte{0, 1, 3, 2}
    b := []byte{0, 1, 3, 2}
    c := []byte{1, 1, 3, 2}

    fmt.Println(bytes.Equal(a, b))
    fmt.Println(bytes.Equal(a, c))
}

计算中文长度

title := "中国人"
fmt.Println(utf8.RuneCountInString(title)) // 输出 3

数据库初始化

什么是 DSN 信息?

DSN 全称为 Data Source Name,表示 数据源信息,用于定义如何连接数据库。不同数据库的 DSN 格式是不同的,这取决于数据库驱动的实现,下面是 go-sql-driver/sql 的 DSN 格式,如下所示:

// [用户名[:密码]@][协议(数据库服务器地址)]]/数据库名称?参数列表
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

如何配置 sql. DB 的 SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime

如何配置 sql. DB 的 SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime

import (
    "github.com/go-sql-driver/mysql"
    _ "github.com/go-sql-driver/mysql" // 引入 mysql 驱动
)

// 初始化单个数据库
func initDB() {
    var err error

    // 设置数据库连接信息
    config := mysql.Config{
        User:                    "root",
        Passwd:                  "123456",
        Net:                     "tcp",
        Addr:                    "127.0.0.1:3305",
        DBName:                  "goblog",
        AllowNativePasswords:    true,
    }

    // 准备数据库连接池
    db, err = sql.Open("mysql", config.FormatDSN())
    checkError(err)

    // 设置最大连接数,不能超过数据库本身设置的最大连接数 `show variables like 'max_connections';`
    db.SetMaxOpenConns(200) // yim 设置了 512
    // 设置最大空闲连接数
    db.SetMaxIdleConns(100) // yim 设置了 256
    // 设置每个连接的过期时间,这里的推荐,比较保守的做法是设置五分钟
    db.SetConnMaxLifetime(5 * time.Minute)

    err = db.Ping()
    checkError(err)
}

func checkError(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

根据结构体返回字段名切片

func main()  {
    // 输出:[ `name`  `password`  `gender`  `create_time`  `update_time`  `id`  `number` ]
    fmt.Println(RawFieldNames(&User{}))
}

const dbTag = "db" // 根据哪个标签获取字段名称

type User struct {
    Name       string `db:"name"` // 用户名称
    Password   string `db:"password"` // 用户密码
    Gender     string `db:"gender"` // 男|女|未公开
    CreateTime time.Time `db:"create_time"`
    UpdateTime time.Time `db:"update_time"`
    Id         int64 `db:"id"`
    Number     string `db:"number"` // 学号
}

func RawFieldNames(in interface{}) []string {
    out := make([]string, 0)
    v := reflect.ValueOf(in)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }

    // we only accept structs
    if v.Kind() != reflect.Struct {
        panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
    }

    typ := v.Type()
    for i := 0; i < v.NumField(); i++ {
        // gets us a StructField
        fi := typ.Field(i)
        if tagv := fi.Tag.Get(dbTag); tagv != "" {
            out = append(out, fmt.Sprintf(" `%s` ", tagv))
        } else {
            out = append(out, fmt.Sprintf( `"%s"` , fi.Name))
        }
    }

    return out
}

移除数组元素

func Remove(strings []string, strs ...string) []string {
    out := append([]string(nil), strings...)

    for _, str := range strs {
        var n int
        for _, v := range out {
            if v != str {
                out[n] = v
                n++
            }
        }
        out = out[:n]
    }

    return out
}

超时处理 & 定时器

// 超时处理
select {
    case <-ch:
    case <-time.After(time.Second * 1): // 1秒后超时触发
        fmt.Println("timeout")
}

// 定时器
count := 0
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
    <-ticker.C
    fmt.Println(count)
    count++
    if count >= 5 {
        break
    }
}

获取真实IP

func GetRemoteAddr(r *http.Request) string {
    v := r.Header.Get("X-Forward-For")
    if len(v) > 0 {
        return v
    }
    return r.RemoteAddr
}

// 获取本机ip
var ip string
func GetLocalIP() string {
    if ip != "" {
        return ip
    }
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        return ""
    }
    for _, address := range addrs {
        // check the address type and if it is not a loopback the display it
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                ip = ipnet.IP.String()
                return ip
            }
        }
    }
    return ""
}

md5 && hmac

func Md5(str string) string {
    h := md5.New()
    h.Write([]byte(str))
    return hex.EncodeToString(h.Sum(nil))
}

func HmacSha256(data string, secret string) string {
    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(data))
    return hex.EncodeToString(h.Sum(nil))
}

// 简单的密码加密方案
func makePassword(pwd string) string {
    return helper.Md5(helper.HmacSha256("盐", pwd))
}

利用反射,结构体转map方法

// 结构体转map方法
func Struct2Map(obj interface{}) map[string]interface{} {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)

    var data = make(map[string]interface{})
    if t.Kind() != reflect.Struct {
        return data
    }

    for i := 0; i < t.NumField(); i++ {
        data[t.Field(i).Name] = v.Field(i).Interface()
    }

    return data
}

// 结构体转map方法,key直接取结构体上变量名的 json 名
func Struct2MapJson(obj interface{}) map[string]interface{} {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)

    var data = make(map[string]interface{})
    if t.Kind() != reflect.Struct {
        return data
    }

    for i := 0; i < t.NumField(); i++ {
        data[t.Field(i).Tag.Get("json")] = v.Field(i).Interface()
    }
    return data
}

// 结构体转map方法,处理嵌套结构体
func StructToMapByJson(obj interface{}) map[string]interface{} {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)

    var data = make(map[string]interface{})
    if t.Kind() != reflect.Struct {
        return data
    }

    for i := 0; i < t.NumField(); i++ {
        value := v.Field(i)

        // 处理嵌套结构体
        t2 := reflect.TypeOf(value.Interface())
        if t2.Kind() == reflect.Struct {
            for j := 0; j < t2.NumField(); j++ {
                temp := t2.Field(j)
                _ = temp
                data[t2.Field(j).Tag.Get("json")] = value.Field(j).Interface()
            }
            continue
        }

        data[t.Field(i).Tag.Get("json")] = value.Interface()
    }

    return data
}

同步队列+并发消费

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

// 同步队列+并发消费案例
type (
    Task struct {
        StartTime time.Time
    }

    TaskManager struct {
        Tasks chan *Task
        Wg    *sync.WaitGroup
        Ctx   context.Context
    }
)

func main() {
    timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) // 10分钟超时
    defer cancel()

    var manager = &TaskManager{
        Tasks: make(chan *Task, 10), // 等待队列10,并发5 执行任务
        Wg:    &sync.WaitGroup{},
        Ctx:   timeoutCtx,
    }

    runDaemon(manager)

    // 生产者:负责生产任务
    var tasks []*Task
    tasks = append(tasks, &Task{})
    for i := 0; i < 20; i++ {
        manager.Wg.Add(1)
        manager.Tasks <- &Task{StartTime: time.Now()}
    }

    manager.Wg.Wait()
}

func runDaemon(manager *TaskManager) {
    // 并发 5 个协程消费队列
    for i := 0; i < 5; i++ {
        go func() {
            for {
                select {
                case task := <-manager.Tasks:
                    // todo 执行相关业务逻辑
                    fmt.Println("消费任务:start_time:", task.StartTime.String())
                    manager.Wg.Done()
                case <-manager.Ctx.Done():
                    return
                }
            }
        }()
    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK