Go-常用方法总结

53 阅读10分钟

1 字符串分割

1.1 根据空格进行分割 strings.Fields(s string) []string

s:= " ab cd          ef gh ij kl "
arr:=strings.Fields(s)
fmt.Printf("arr:%q\n",arr)

输出 arr:["ab" "cd" "ef" "gh" "ij" "kl"]

注意:分割出来的元素不会是空格,元素内部也不包含空格,元字符串如果存在多个空格也照样进行分割。

1.2 根据某个字符串对另一个字符串进行分割 strings.Split(str string, sep string) []string

str:= "iiaiibiiciiiidiiii"
sep:= "ii"
arr:=strings.Split(str, sep)
fmt.Println("arr:", arr)

输出 arr:["" "a" "b" "c" "" "d" "" ""]

可以看出,这里是直接将分隔符替换成了空字符串,然后组成列表。

注意:当 sep = ""时,会根据""进行分割,即结果为:arr:["i" "i" "a" "i" "i" "b" "i" "i" "c" "i" "i" "i" "i" "d" "i" "i" "i" "i"]

2 InArray:某个元素是否在某个列表里面

func newInArray(needle interface{}, haystack interface{}) bool {
	haystackValue := reflect.ValueOf(haystack)
	haystackKind := haystackValue.Kind()
	if haystackKind == reflect.Slice || haystackKind == reflect.Array {
		length := haystackValue.Len()
		for i := 0; i < length; i++ {
			if haystackValue.Index(i).Interface() == needle {
				return true
			}
		}
	}
		
	return false
}
func InArray[T comparable](needle T, haystack []T) bool {
   for _, item := range haystack {
      if item == needle {
         return true
      }
   }
   return false
}

3,字符串前缀判断

package main

func main() {
	a := BeginWith("abc", "a")
	println(a) // 输出true
}

func BeginWith(fullString string, prefix string) bool {
	return fullString[0: len(prefix)] == prefix
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

4,正则过滤字符串

package main

import (
	"fmt"
	"regexp"
)

func main() {
	pattern := "[^A-Za-z0-9_\-\u4e00-\u9fcb\u3400-\u4DB5\u20000-\u2A6D6\u2A700-\u2B734\u2A740-\u2B81D]"
	reg1 := regexp.MustCompile(pattern)
	if reg1 == nil {
		fmt.Println("regexp err")
		return
	}
	match := reg1.ReplaceAllString("abc*def汉字&ghi", "")

	fmt.Println(match)
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

输出

abcdef汉字ghi

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

regexp.Split 正则分割字符串

package main

import (
	"fmt"
	"regexp"
)

func main() {
	re := regexp.MustCompile("[0-9]+")
	txt := "Have9834a908123great10891819081day!"

	split := re.Split(txt, -1)
	set := []string{}

	for i := range split {
		set = append(set, split[i])
	}

	fmt.Println(set) // ["Have", "a", "great", "day!"]
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

5,用一个变量传入和使用多个类型的参数值

package main

import "fmt"

func main() {
	multiParam(1, "a", 3.0)
}

func multiParam(params ...interface{}) {
	str := fmt.Sprintf("param0:%d,param1:%s,param2:%f", params...)
	fmt.Println(str)
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

 这里的 ... 和 PHP 的 ... 使用基本一致。而 ... 后面的 interface{} 表明每个传值的类型可以是不固定的。

输出

param0:1,param1:a,param2:3.000000

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

6,当数据类型不确定或者不固定时,可以使用interface{},在1.18中,也可以使用 any,它其实就是interface{}的别名。

package main

import (
	"fmt"
)

func main() {
	var a interface{} // 定义一个interface类型的变量

	a = funcA(1)
	fmt.Println(a)

	a = funcB("b")
	fmt.Println(a)

    a = funcC(2, "")
	fmt.Println(a)

	a = funcC(0, "c")
	fmt.Println(a)

	a = funcC(0, "")
	fmt.Println(a)
}

func funcA(intA int) int {
	return intA
}

func funcB(stringB string) string {
	return stringB
}

// 返回interface类型的数据
func funcC(intA int, stringB string) interface{} {
	if intA != 0 {
		return intA
	}

	if stringB != "" {
		return stringB
	}

	return nil
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

输出

1
b
2
c
<nil>

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

7,判断某个结构体里面是否存在某个方法

package main

import (
	"fmt"
	"reflect"
)

type HaystackStruct struct{}

func main() {
	methodExists := MethodExists(&HaystackStruct{}, "FuncA")
	fmt.Println(methodExists)
}

// 要查询的方法
func (hs *HaystackStruct) FuncA(data interface{}, name string) string {
	data2 := data.(string) + "===" + name
	return data2
}

// 判断结构体方法是否存在
func MethodExists(haystackStruct interface{}, toSearchMethodName string) bool {
	if toSearchMethodName == "" {
		return false
	}
	p := reflect.TypeOf(haystack)
    
    // 这里的判断只在1.18版本及以上才适用
	if p.Kind() == reflect.Pointer {
		p = p.Elem()
	}
    // 1.16写法
    if p.Kind() == reflect.Ptr {
		p = p.Elem()
	}
	// 不是结构体时
	if p.Kind() != reflect.Struct {
		return false
	}
	object := reflect.ValueOf(haystackStruct)
	// 获取到方法
	newMethod := object.MethodByName(toSearchMethodName)
	if !newMethod.IsValid() {
		return false
	}
	return true
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

输出

true

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

8,获取当前方法的名称

package main

import (
	"fmt"
	"runtime"
	"strings"
)

func main() {
	funcA()
}

func funcA() {
	selfFunctionName := GetSelfFunctionName()
	fmt.Println(selfFunctionName)
  
    callerFunctionName := GetCallerFunctionName()
    fmt.Println(callerFunctionName)
}

// 获取当前运行方法名称:谁调用此方法,就返回谁的方法名称
func GetSelfFunctionName() string {
	pc := make([]uintptr, 1) // 第二个参数至少是1
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
    // 这里输出的堆栈文件、行号、包.方法名称
	fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
	functionList := strings.Split(frame.Function, ".")
	if len(functionList) >= 2 {
		return functionList[1]
	} else {
		return functionList[0]
	}
}

// 获取上级调用方的方法名称:A调用B,B调用本方法,返回A的名称
func GetCallerFunctionName() string {
	pc := make([]uintptr, 1) // 第二个参数至少是1
	n := runtime.Callers(2, pc)
	frames := runtime.CallersFrames(pc[:n])
	frame, _ := frames.Next()
    // 这里输出的堆栈文件、行号、包.方法名称
	fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
	functionList := strings.Split(frame.Function, ".")
	return functionList[0]
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

输出

/tmp/sandbox1151095896/prog.go:14 main.funcA
funcA
/tmp/sandbox1151095896/prog.go:17 main.funcA
main

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

9,根据方法名称和后缀列表拼接实际方法名,然后依次执行。这个方法有一个缺点,就是传参只能是简单的数据类型,不支持struct,原因是Call()方法的参数只能是[]Value 类型,不支持带 key 的数据。

package main

import (
	"fmt"
	"reflect"
	"errors"
)

type StructA struct {
}

type requestStruct struct {
	ProjectID string `json:"project_id"`
	OrgID string `json:"org_id"`
}

func main() {
	requestStruct := requestStruct{
		ProjectID: "prj-xxx",
		OrgID: "org-yyy",
	}
	response, err := ProcessMethodsWithSuffix(&StructA{}, "Func", []string{"A", "B"}, requestStruct)
	if err != nil {
		fmt.Println(fmt.Sprintf("error: %v", err))
	}
	fmt.Println(fmt.Sprintf("response: %v", response[0]))
}

func (s *StructA) FuncA(param ...interface{}) (interface{}, error) {
	return fmt.Sprintf("this is funcA: %v", param...), nil
}

func (s *StructA) FuncB(param ...interface{}) (interface{}, error) {
	return fmt.Sprintf("this is funcB: %v", param...), errors.New("empty name")
}

// 依次执行多个方法,每个方法返回一个interface
func ProcessMethodsWithSuffix(structObject interface{}, methodName string, methodSuffixList []string, params ...interface{}) ([]interface{}, error) {
	var result []interface{}

	// 调用对象
	toProcessStruct := reflect.ValueOf(structObject)
	// 方法名称,如果传空,就默认用调用方的名称
	if methodName == "" {
		//methodName = GetCallerFunctionName()
	}
	if methodName == "" {
		return result, nil
	}

	// 方法后缀列表,默认是Common和Individual
	if len(methodSuffixList) == 0 {
		methodSuffixList = []string{"A", "B"}
	}
	if len(methodSuffixList) == 0 {
		return result, nil
	}

	// 参数
	toProcessParam := []reflect.Value{}
	for _, param := range params {
		toProcessParam = append(toProcessParam, reflect.ValueOf(param))
	}

	// 将方法名和后缀拼接成实际方法名,依次执行,有任何error则return
	for _, methodSuffix := range methodSuffixList {
		toProcessMethodName := methodName + methodSuffix
		if IsMethodExists(structObject, toProcessMethodName) {
			processResult := toProcessStruct.MethodByName(toProcessMethodName).Call(toProcessParam)
			// 所调用的方法必须只有2个返回值,第二个一定是error类型
			if len(processResult) != 2 {
				return result, errors.New(fmt.Sprintf("Bad Request: %s", toProcessMethodName))
			}
			if err, ok := processResult[1].Interface().(error); ok {
				return result, errors.New(fmt.Sprintf("%s", err))
			}

			result = append(result, processResult[0])
		}
	}

	return result, nil
}

// 判断结构体方法是否存在
func IsMethodExists(haystackStruct interface{}, toSearchMethodName string) bool {
	if toSearchMethodName == "" {
		return false
	}
	p := reflect.TypeOf(haystackStruct)
	if p.Kind() == reflect.Ptr {
		p = p.Elem()
	}
	// 不是结构体时
	if p.Kind() != reflect.Struct {
		return false
	}
	object := reflect.ValueOf(haystackStruct)
	// 获取到方法
	newMethod := object.MethodByName(toSearchMethodName)
	if !newMethod.IsValid() {
		return false
	}
	return true
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

输出

error: empty name
response: this is funcA: {prj-xxx org-yyy}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

6,类型转换

6.1 int类转字符串

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var a int
	a = 1
	b := string(a)
	fmt.Println(b)  // 输出空字符串
	a += 1
	b = strconv.Itoa(a)
	fmt.Println(b)  // 输出2

	var c int8
	c = 8
	d := fmt.Sprint(c)
	fmt.Println(d) // 输出8

	var e int32
	e = 32
	f := fmt.Sprint(e)
	fmt.Println(f) // 输出32

	var g int64
	g = 64
	h := strconv.FormatInt(g, 10)
	fmt.Println(h) // 输出64
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

可以看出 int 用 strconv.Itoa(),int8和int32用fmt.Sprint(),int64用 strconv.FormatInt(x, 10) 。

6.2 数值型字符串转成int型

package main

import (
	"fmt"
	"strconv"
)

func main() {

	var a string
	a = "123"
	b, err := strconv.Atoi(a)
	if err != nil {
		fmt.Println(fmt.Sprintf("strconv.Atoi err:%+v", err))
	}
	fmt.Println(b) // 输出123

	a = "-456"
	c, err := strconv.ParseInt(a, 10, 64)
	if err != nil {
		fmt.Println(fmt.Sprintf("strconv.ParseInt err:%+v", err))
	}
	fmt.Println(c) // 输出-456

	a = "789"
	d, err := strconv.ParseUint(a, 10, 64)
	if err != nil {
		fmt.Println(fmt.Sprintf("strconv.ParseUint err:%+v", err))
	}
	fmt.Println(d) // 输出789
}

 可以看到,不带符号直接转int可以用 strconv.Atoi(),转特定的位数可以用strconv.ParseInt(),带符号用 strconv.ParseUint()。

7,字符串列表拼接成字符串

package main

import "fmt"

func main() {
	a := []string{"Project", "Organization", "Global"}
	b := JoinListToString(a, ",")
    fmt.Println(b) // 输出"Project,Organization,Global"
}

// JoinListToString 将字符串列表拼接成字符串
func JoinListToString(list []string, glue string) string {
	length := len(list)
	if length == 0 {
		return ""
	} else if length == 1 {
		return list[0]
	}

	var result string
	for i := 0; i < length; i++ {
		if i == length - 1 {
			result += list[i]
		} else {
			result += list[i] + glue
		}
	}
	return result
}

转存失败,建议直接上传图片文件转存失败,建议直接上传图片文件

8,判断某个map中是否存在某个key: value, ok := mapA[key] ,ok为true就是存在

package main

import (
	"fmt"
)

func main() {
	mapA := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
	}
	for _, key := range []string{"a", "d"} {
		value, ok := mapA[key]
		if ok {
			fmt.Println(fmt.Sprintf("key:%v exist value: %v", key, value))
		} else {
			fmt.Println(fmt.Sprintf("key:%v not exist", key))
		}
	}
}

输出

key:a exist value: 1
key:d not exist

9 根据结构体中某个字段进行排序,可使用 sort.Sort()函数

package main
     
import (
    "fmt"
    "sort"
)

type Fruit struct {
    Name string
    Number int
}

func main() {
    items := []Fruit{
        {"apple", 7},
            {"orange", 3},
        {"banana", 6},
        {"cherry", 1},
    }

    // 按Name字段从小到大按字母排序
    sort.Slice(items, func(i, j int) bool {
        return items[i].Name < items[j].Name
    })
    fmt.Println(fmt.Sprintf("items: %+v", items))

    // 按Number字段从大到小排序
    sort.Slice(items, func(i, j int) bool {
        return items[i].Number > items[j].Number
    })
    fmt.Println(fmt.Sprintf("items: %+v", items))
}

输出

items: [{Name:apple Number:7} {Name:banana Number:6} {Name:cherry Number:1} {Name:orange Number:3}]
items: [{Name:apple Number:7} {Name:banana Number:6} {Name:orange Number:3} {Name:cherry Number:1}]