golang常用技巧

目录

一、判断元素是否存在数组中

二、判断俩数组(slice)是否相等

三、经典的Map,相同Key的对应值累加

四、保留小数点

五、int64、int、string转换

六、去掉最后一个符号

七、切割大法(split)

八、golang判断key是否在map中

九、月份筛选

十、遍历map

十一、Json 结构体转换

十二、判断数组是否有重复元素

十三、结构体动态加变量

十四、结构体(struct) 转化成map(Golang反射)

十五、时间处理

十六、struct转interface

十七、interface转struct

十八、结构体排序:(内存排序)

十九、千分位转换

二十、判断变量为空或者是空格

二十一、通过反射,获取结构体变量的字段名称

二十二、生成excel字母表头

二十三、捕获panic

二十四:等待 goroutine 完成任务

二十五、经典毫秒加1小时


一、判断元素是否存在

数组中

封装函数:

func IsContain(items []string, item string) bool {
    for _, eachItem := range items {
        if eachItem == item {
            return true
        }
    }
    return false
}

使用方法:

var word := "my"
var sentence := []string{"my","word","in","a","sentence"}
if IsContain(sentence,word){
    //包含
    }else{
    //不包含
    }

二、判断俩数组(slice)是否相等

前提是确定slice的类型,下面的示例是string类型

func StringSliceEqual(a, b []string) bool {
    if len(a) != len(b) {
        return false
    }
    if (a == nil) != (b == nil) {
        return false
    }
    for i, v := range a {
        if v != b[i] {
            return false
        }
    }
    return true
}

int类型

func testEq(a, b []int) bool {
    // If one is nil, the other must also be nil.
    if (a == nil) != (b == nil) {
        return false;
    }
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

用法:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    b := []int{1, 3, 2, 4}
    c := []int{1, 2, 3, 4}
    fmt.Println(testEq(a, b))
    fmt.Println(testEq(a, c))
}

四、保留小数点

func Decimal(value float64) float64 {
    value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
    //加上 0.5是为了四舍五入,想保留几位小数的话把2改掉即可。
    return value
}

func Decimal(value float64) float64 {
    //先通过Sprintf保留两位小数,再转成float64.
    return math.Trunc(value*1e2+0.5) * 1e-2
}

五、int64、int、string转换

1、int转string

var a int
a = 1
strconv.Itoa(a)

2、int64转string

var a int64
a = 1
strconv.FormatInt(a, 10

3、string转int

int,err:=strconv.Atoi(string)

4、string转int64

int64, err := strconv.ParseInt(string, 10, 64)

5、float 转string

var a float64
decimal.NewFromFloat(a).String()

var b float32
decimal.NewFromFloat(b).String()

6、string转float64

float64, _ := strconv.ParseFloat("100", 64)

7、string转uint8

func main() {
    width := "42"
    u64, err := strconv.ParseUint(width, 10, 8)
    if err != nil {
        fmt.Println(err)
    }
    wd := uint(u64)
    fmt.Println(wd)
}

六、去掉最后一个符号

 //去掉最后一个 逗号(,)
values = strings.TrimRight(values, ",") 

// 去掉最左边的这串字符串 "xx有限公司/"
absPath = strings.TrimLeft(absPath, "xx有限公司/")

七、切割大法(split)

Go语言分割字符串-Golang字符串分割-Golang Split-Go语言按空格分割字符串-嗨客网

按字符串分割字符串

使用 strings.Split 函数,实现按字符串分割字符串

Python版:

# 取出下面这个url中marker的值
thishref="https://testcloud.com/v2/059bcffb728026a52ffbc019f720242f/os-vendor-volumes/detail?offset=1&marker=5023bd51-7ca2-4cf0-bf8a-357922ab77f9&limit=1000"
for tgl in thishref.split("&"):
    if tgl != "":
        (key,value) = tgl.split("=")
        if key=="marker":
            thisMarker=value
print(thisMarker)
结果:
5023bd51-7ca2-4cf0-bf8a-357922ab77f9

Golang版本:

//将row.TagDept的值格式化取出,比如:(Dept,pcoffice;Name,V9_VPN_JP) ,最终要取出 pcoffice
thisTagDept := ""
if row.TagDept != "" {
    tagDeptList := strings.Split(row.TagDept, ";")
    for _, dd := range tagDeptList {
        if dd != "" {
            tagDeptKV := strings.Split(dd, ",")
            key := ""
            val := ""
            if len(tagDeptKV) > 1 {
                key = tagDeptKV[0]
                val = tagDeptKV[1]
            }
            if key == "Dept" {
                thisTagDept = val
            }
        }
    }
}

按空格分割字符串

使用 strings.Fields 函数,实现按空格分割字符串

可识别多个空格

tag2 := strings.Fields(" ew ewew e")

fmt.Println("len2:", len(tag2 ), tag2 )

八、golang判断key是否在map中

if _, ok := map[key]; ok {
//存在
}

if _, ok := map[key]; !ok {
//不存在
}

十、遍历map

    for key, value := range aMap {
        fmt.Println("key:", key, "value:", value)
    }

十一、Json 结构体转换

  1. 结构体转json,使用json.Marshal()返回值([]byte, error)
package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Name string
    Age int
    Gender byte
    Subject []string
}


func main() {
    s := Student{
        "XiaoMing",
        15,
        'M',
        []string{"数学","语文","英语"},
    }
    sJson,err := json.Marshal(s)
    if err!=nil{
        fmt.Println(err)
        return
    }
    fmt.Println("json of s = ",string(sJson))
}
  1. json转结构体,使用json.Unmarshal([]byte(string),*s)
package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Name string  //“-”字段转换成json时舍弃
    Age int
    Gender byte
    Subject []string
}
func main() {
    str := `{
        "name":"李雷",
        "age": "15",
        "gender": 77,
        "subject": [
            "数学",
            "语文",
            "英语"
        ]
    }`
    s:= new(Student)
    json.Unmarshal([]byte(str),s)//第二个参数必须是指针
    fmt.Println(*s)
}

十二、判断数组是否有重复元素

func IsHaveDuplicate(lists []string) bool {
    //判断数组是否有重复元素
    maps := make(map[string]string)
    flag := false
    for _, w := range lists {
        _, ok := maps[w]
        if ok {
            flag = true
            break
        }
        maps[w] = " "
    }
    return flag
}

十三、结构体动态加变量

参考:golang json数组拼接_pingd的博客-CSDN博客_go 数组拼接

思路:结构体序列化成[]byte数组后,再从[]byte数组序列化成结构体(map[string]interface{} )后,加key

    type dataS struct {
        A string
        B string
    }
    var data dataS
    data = dataS{
        A: "aa",
        B: `所得税:{"bb"}//http://ww.com?ss=1`,
    }
    fmt.Printf("原结构体:%+v \n", data)
    
    //将固定的结构体转为json后加元素;思路:
    jsonData, _ := json.Marshal(data)
    fmt.Println("转为json: ", string(jsonData))
    //动态给json加key-value
    tmpMap := make(map[string]interface{})
    err := json.Unmarshal(jsonData, &tmpMap)
    if err != nil {
        fmt.Println("json反序列化失败:", err)
    }
    tmpMap["id"] = "666"
    jsonData2, _ := json.Marshal(tmpMap)
    fmt.Println("添加了元素后:", string(jsonData2))

    fmt.Println("\n华丽的分隔符--------------------------------------------------------------\n")

json动态加元素

思路:  //把原有json加元素转为map[string]interface{}后,加key,然后转为json

 
    str1 := `{"id":116910728,"content":{"department_id":"120288184012640258","business_tags":"[\"ERERER\",\"666\"]"}}`
    inte := make(map[string]interface{})

    if err := json.Unmarshal([]byte(str1), &inte); err != nil {
        inte = map[string]interface{}{}
    }
    fmt.Printf("转换为结构体:%+v \n", inte)
    inte["new_key"] = "aaabbb"

    addStr1, _ := json.Marshal(inte)
    fmt.Println("添加了元素后:", string(addStr1))

十四、结构体(struct) 转化成map(Golang反射)

参考:Golang反射:结构体(struct) 转化成map - 知乎

map转struct

https://www.jianshu.com/p/0ceee1a4a0ae

方式一、通过mapstructure.Decode()方法

可以通过github.com/mitchellh/mapstructure包的mapstructure.Decode(map[string]interface,*struct)方法将map转换成结构体,该方法的参数有两个,

第一个参数是要转换的map变量,

第二个参数是struct结构体变量指针,

下面通过一个例子说明mapstructure.Decode()函数的使用方法,如:

"""
注意的点:
1、map[string]interface的键值将对应字段赋值到结构体时忽略大小写;
2、结构体中所有字段名必须以大写字母开头,否则将无法赋值
3、使用mapstructure.Decode()方法不能转化携带_特殊符号的变量
"""
package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
)
type student struct{
    id int `json:"id"`
    Name string `json:"name"`
    Adress []string `json:"adress"`
}
func main() {
    val := map[string]interface{}{
        "id":1,
        "name":"xiaoming",
        "adress":[]string{"beijing","nanjing"},
    }
    stu := student{}
    err := mapstructure.Decode(val,&stu)
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Println("val:")
    fmt.Println(val)
    fmt.Println("struct:")
    fmt.Println(stu)
}

运行结果

val:
map[adress:[beijing nanjing] id:1 name:xiaoming]
struct:
{1 xiaoming [beijing nanjing]}

方式二、通过json序列化和反序列化实现map到struct的转换

参考示例:

package main

import (
    "encoding/json"
    "fmt"
)
type student struct{
    id int `json:"id"`
    Name string `json:"name"`
    Adress []string `json:"adress"`
    PhoneNumber string `json:"phone_number"`
}
func main() {
    val := map[string]interface{}{
        "id":1,
        "name":"xiaoming",
        "adress":[]string{"beijing","nanjing"},
        "phone_number":"12345678",
    }
    stu := student{}
    arr,err := json.Marshal(val)
    if err != nil {
        fmt.Println(err)
        return
    }
    err = json.Unmarshal(arr,&stu)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("val:")
    fmt.Println(val)
    fmt.Println("struct:")
    fmt.Println(stu)
}

运行结果:

val:
map[adress:[beijing nanjing] id:1 name:xiaoming phone_number:12345678]
struct:
{0 xiaoming [beijing nanjing] 12345678}

十五、时间处理

1、使用time.Unix()函数可以将unix时间格式转换为时间戳格式

a := time.Unix(1632363000, 0)
fmt.Println(a)
fmt.Println(reflect.TypeOf(a))

返回:
2021-09-23 10:10:00 +0800 CST
time.Time

2、时间转字符串

timeStr:=time.Now().Format("2006-01-02 15:04:05")  
//当前时间的字符串,2006-01-02 15:04:05据说是golang的诞生时间,固定写法

十八、结构体排序:(内存排序)

通用版:https://www.jianshu.com/p/ef66fd979050

GO语言为结构体排序 - Go语言中文网 - Golang中文社区

通用版代码示例:

package main

import (
    "fmt"
    "reflect"

    "sort"
)

type User struct {
    Name        string  `json:"name"`
    Create_time string  `json:"create_time"`
    Sum         float64 `json:"sum"`
}

//通用排序
//结构体排序,必须重写数组Len() Swap() Less()函数
type body_wrapper struct {
    Bodys []interface{}
    by    func(p, q *interface{}) bool //内部Less()函数会用到
}
type SortBodyBy func(p, q *interface{}) bool //定义一个函数类型

//数组长度Len()
func (acw body_wrapper) Len() int {
    return len(acw.Bodys)
}

//元素交换
func (acw body_wrapper) Swap(i, j int) {
    acw.Bodys[i], acw.Bodys[j] = acw.Bodys[j], acw.Bodys[i]
}

//比较函数,使用外部传入的by比较函数
func (acw body_wrapper) Less(i, j int) bool {
    return acw.by(&acw.Bodys[i], &acw.Bodys[j])
}

//自定义排序字段,参考SortBodyByCreateTime中的传入函数
//func SortBody(bodys []interface{}, by SortBodyBy) {
//    sort.Sort(body_wrapper{bodys, by})
//}

func SortBody(bodys []interface{}, sortField string, desc bool) {
    sort.Sort(body_wrapper{bodys, func(p, q *interface{}) bool {
        v := reflect.ValueOf(*p)
        i := v.FieldByName(sortField)
        v = reflect.ValueOf(*q)
        j := v.FieldByName(sortField)
        if desc {
            return i.Float() > j.Float()
        } else {
            return i.Float() < j.Float()
        }

    }})
}

//按照createtime排序,需要注意是否有createtime
func SortBodyByCreateTime(bodys []interface{}) {
    sort.Sort(body_wrapper{bodys, func(p, q *interface{}) bool {
        v := reflect.ValueOf(*p)
        i := v.FieldByName("Create_time")
        v = reflect.ValueOf(*q)
        j := v.FieldByName("Create_time")
        return i.String() > j.String()
    }})
}

func main() {
    results := []interface{}{} //这里必须定义成[]interface{}{}
    u1 := User{
        Name:        "lxw",
        Create_time: "2018-02-01",
        Sum:         90.5,
    }
    u2 := User{
        Name:        "zll",
        Create_time: "2018-03-01",
        Sum:         90.6,
    }
    results = append(results, u1)
    results = append(results, u2)
    //使用定义好的排序
    SortBodyByCreateTime(results)
    fmt.Println(results)
    // 使用自定义的字段排序
    SortBody(results, "Sum", true)
    fmt.Println(results)
}

十九、千分位转换

golang 处理数字3位一组展示,中间用逗号分开 - Go语言中文网 - Golang中文社区

package main

import (
    "fmt"
    "strings"
)

func main() {
    strResult := NumberFormat("1234567898.55")
    fmt.Println(strResult)
}

//格式护数值    1,234,567,898.55
func NumberFormat(str string) string {
    length := len(str)
    if length < 4 {
        return str
    }
    arr := strings.Split(str, ".") //用小数点符号分割字符串,为数组接收
    length1 := len(arr[0])
    if length1 < 4 {
        return str
    }
    count := (length1 - 1) / 3
    for i := 0; i < count; i++ {
        arr[0] = arr[0][:length1-(i+1)*3] + "," + arr[0][length1-(i+1)*3:]
    }
    return strings.Join(arr, ".") //将一系列字符串连接为一个字符串,之间用sep来分隔。
}

二十、判断变量为空或者是空格

    wpsSid := "   "
    if len(strings.Trim(wpsSid, " ")) == 0 {
        fmt.Println("wpsSid is empty")
    }

二十一、通过反射,获取结构体变量的字段名称

package main

import (
    "fmt"
    "reflect"
)

type User2 struct {
    Name        string  `json:"name"`
    Create_time string  `json:"create_time"`
    Sum         float64 `json:"sum"`
}

func GetStructFieldNameMap(dataV interface{}) map[string]string {
    var dataFieldMap = make(map[string]string)
    reType := reflect.TypeOf(dataV)

    for j := 0; j < reType.NumField(); j++ {
        fieldName := reflect.TypeOf(dataV).Field(j).Name
        jsonName := reflect.TypeOf(dataV).Field(j).Tag.Get("json")
        dataFieldMap[jsonName] = fieldName
    }

    return dataFieldMap
}

func main() {
    var U1 = User2{
        Name:        "a",
        Create_time: "2022",
        Sum:         2022,
    }

    //var U2 = User2{}  也可以不赋值

    aMap := GetStructFieldNameMap(U1)
    fmt.Println("dataFieldMap:", aMap)
}

执行结果:

二十二、生成excel字母表头

package main
import "fmt"
// 根据下标 获取 Excel对应表头字母
func GetExcelKey(index int) string {
   colCode := ""
   key := 'A'
   loop := index / 26
   if loop > 0 {
      colCode += GetExcelKey(loop - 1)
   }
   return colCode + string(key+int32(index)%26)
}

func main() {
   fmt.Println(GetExcelKey(0))
   fmt.Println(GetExcelKey(26))
   fmt.Println(GetExcelKey(45))
}

二十三、捕获panic

Golang 错误捕获 Panic 与 Recover_猫轻王的博客-CSDN博客_golang panic recover

package main

import (
    "fmt"
    "runtime/debug"
)

func main() {

// 当使用defer 时,将会在程序内方法结算后,
// 依照后进先出的方法执行defer内方法
// 此时就能保证 捕获程序一定能捕获到错误
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("get panic", r)
            fmt.Println("panic堆栈信息:", string(debug.Stack()))
        }
    }()

    fmt.Println("start...")

    count := [2]int{5, 7}

    for i := 0; i < 3; i++ {
        fmt.Println(count[i])
    }

    fmt.Println("ok...")

}

二十四:等待 goroutine 完成任务

Golang 入门 : 等待 goroutine 完成任务 - 走看看

参考官网https://tutorialedge.net/golang/go-waitgroup-tutorial/

Golang 官方在 sync 包中提供了 WaitGroup 类型来解决这个问题。其文档描述如下:

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

大意为:WaitGroup 用来等待单个或多个 goroutines 执行结束。在主逻辑中使用 WaitGroup 的 Add 方法设置需要等待的 goroutines 的数量。在每个 goroutine 执行的函数中,需要调用 WaitGroup 的 Done 方法。最后在主逻辑中调用 WaitGroup 的 Wait 方法进行阻塞等待,直到所有 goroutine 执行完成。

使用方法可以总结为下面几点:

1、创建一个 WaitGroup 实例,比如名称为:wg
2、调用 wg.Add(n),其中 n 是等待的 goroutine 的数量
3、在每个 goroutine 运行的函数中执行 defer wg.Done()
4、调用 wg.Wait() 阻塞主逻辑

运行下面的代码:

package main

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

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    say2("hello", &wg)
    say2("world", &wg)
    fmt.Println("over!")
}

func say2(s string, waitGroup *sync.WaitGroup) {
    defer waitGroup.Done()

    for i := 0; i < 3; i++ {
        fmt.Println(s)
    }
}

输出的结果如下:

hello
hello
hello
world
world
world
over!

下面是一个稍稍真实一点的例子,检查请求网站的返回状态。如果要在收到所有的结果后进一步处理这些返回状态,就需要等待所有的请求结果返回:

package main

import (
    "fmt"    "sync"    "net/http")

func main() {
    var urls = []string{
        "https://www.baidu.com/",
        "https://www.cnblogs.com/",
    }

    var wg sync.WaitGroup

    for _, url := range urls {
        wg.Add(1)
        go fetch(url, &wg)
    }

    wg.Wait()
}

func fetch(url string, wg *sync.WaitGroup) (string, error) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println(err)
        return "", err
    }
    fmt.Println(resp.Status)
    return resp.Status, nil
}

运行上面的代码,输出的结果如下:

200 OK
200 OK

二十五、经典毫秒加1小时

    //毫秒加1小时
    var StartTime, EndTime int64
    StartTime = 1657782000000
    EndTime = 1657792800000
    fmt.Println(time.UnixMilli(StartTime), time.UnixMilli(EndTime))
    var bw = []int64{1, 23, 5}
    for sampleAt := StartTime; sampleAt < EndTime; sampleAt = sampleAt + 3600*1000 {
        fmt.Println(time.UnixMilli(sampleAt))
    }

    for i := range bw {
        fmt.Println(bw[i], time.UnixMilli(StartTime+3600*1000*int64(i)))
    }
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值