Golang实践录:我的工具包

it2023-05-02  68

程序员难免会自造轮子,因为有时候自己的轮子才更适合自己,golang 的生态圈不错,官方的,非官方都有很多不同功能的库。本文从小处着眼,基于 github 开源工程创建属于自己的工具包。

简单介绍

本文的工具包,不依赖第三方库,全部使用官方的包。实际中使用了第三方库,则另起目录,作为其它包提供。不影响本包。本包命名为 com,可理解为通用的包。包括但不限于以下内容: 数值和字符串转换,进制转换。 目录、文件操作。 日期、时间。 命令执行。 MD5、base64。 地址内容打印Dump。

模块介绍

本小节列出一些函数的实现,详细参考文后源码地址。

字符串和数值转换

字符串转为数值:

// Convert string to specify type. type StrTo string func (f StrTo) Exist() bool { return string(f) != string(0x1E) } func (f StrTo) Uint8() (uint8) { v, _ := strconv.ParseUint(f.String(), 10, 8) return uint8(v) } func (f StrTo) Int() (int) { v, _ := strconv.ParseInt(f.String(), 10, 0) return int(v) } func (f StrTo) Int64() (int64) { v, _ := strconv.ParseInt(f.String(), 10, 64) return int64(v) } func (f StrTo) Float64() (float64) { v, _ := strconv.ParseFloat(f.String(), 64) return float64(v) } func (f StrTo) Uint8Hex() (uint8) { v, _ := strconv.ParseUint(f.String(), 16, 8) return uint8(v) } func (f StrTo) IntHex() (int) { v, _ := strconv.ParseInt(f.String(), 16, 0) return int(v) } func (f StrTo) Int64Hex() (int64) { v, _ := strconv.ParseInt(f.String(), 16, 64) return int64(v) } func (f StrTo) String() string { if f.Exist() { return string(f) } return "" }

可根据不同函数,将字符串转换成对应的数值。注意,此处不判断原始字符串,通过不同函数指定格式。如256,即可认为十进制,也可认为是十六进制。

数值转换为字符串:

// Convert any type to string. func ToStr(value interface{}, args ...int) (s string) { switch v := value.(type) { case bool: s = strconv.FormatBool(v) case float32: s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32)) case float64: s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64)) case int: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int8: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int16: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int32: s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) case int64: s = strconv.FormatInt(v, argInt(args).Get(0, 10)) case uint: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint8: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint16: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint32: s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) case uint64: s = strconv.FormatUint(v, argInt(args).Get(0, 10)) case string: s = v case []byte: s = string(v) default: s = fmt.Sprintf("%v", v) } return s }

十六进制和字符串转换:

// HexStr2int converts hex format string to decimal number. func HexStr2int(hexStr string) (int) { num := 0 length := len(hexStr) for i := 0; i < length; i++ { char := hexStr[length-i-1] factor := -1 switch { case char >= '0' && char <= '9': factor = int(char) - '0' case char >= 'a' && char <= 'f': factor = int(char) - 'a' + 10 default: return -1 } num += factor * PowInt(16, i) } return num } // Int2HexStr converts decimal number to hex format string. func Int2HexStr(num int) (hex string) { if num == 0 { return "0" } for num > 0 { r := num % 16 c := "?" if r >= 0 && r <= 9 { c = string(r + '0') } else { c = string(r + 'a' - 10) } hex = c + hex num = num / 16 } return hex }

缓冲区、结构体打印

缓冲区打印:

func Dump(by []byte, len int) { line := 16 n := len / line if len % line != 0 { n++ } for i := 0; i < n; i++ { fmt.Printf("%08x ", i*line) for j := 0; j < line; j++ { if i*line+j < len { fmt.Printf("%02x ", by[i*line+j]) } else { fmt.Printf(" ") } if j == 7 { fmt.Printf(" ") } } fmt.Printf(" |") for j := 0; j<line && (i*line+j)<len; j++ { if (i*line+j) < len { c := by[i*line+j] if c >= ' ' && c < '~'{ fmt.Printf("%c", c) } else { fmt.Printf(".") } } else { fmt.Printf(" ") } } fmt.Printf("|\n") } }

该函数实际为笔者 C 语言版本的改写。

结构体或map的打印:

// 将数组、map等,按行打印,默认fmt.Println是一行 func PrintByLine(w io.Writer, data interface{}) { if w == os.Stderr { fmt.Fprintf(os.Stderr, "error: ") } t := reflect.TypeOf(data) v := reflect.ValueOf(data) if v.Len() == 0 { return } fmt.Fprintf(w, "[\n") switch t.Kind() { case reflect.Slice, reflect.Array: for i := 0; i < v.Len(); i++ { fmt.Fprintf(w, "%d %v\n", i+1, v.Index(i)) } case reflect.Map: iter := v.MapRange() i := 0 for iter.Next() { fmt.Fprintf(w, "%d %v: %v\n", i+1, iter.Key(), iter.Value()) i += 1 } default: fmt.Fprintf(w, "%v\n", data) } fmt.Fprintf(w, "]\ntotal: %d\n", v.Len()) }

时间相关

// Format unix time int64 to string func Date(ti int64, format string) string { t := time.Unix(int64(ti), 0) return DateT(t, format) } // Format unix time string to string func DateS(ts string, format string) string { i, _ := strconv.ParseInt(ts, 10, 64) return Date(i, format) } // Format time.Time struct to string // MM - month - 01 // M - month - 1, single bit // DD - day - 02 // D - day 2 // YYYY - year - 2006 // YY - year - 06 // HH - 24 hours - 03 // H - 24 hours - 3 // hh - 12 hours - 03 // h - 12 hours - 3 // mm - minute - 04 // m - minute - 4 // ss - second - 05 // s - second = 5 // TODO ms func DateT(t time.Time, format string) string { res := strings.Replace(format, "MM", t.Format("01"), -1) res = strings.Replace(res, "M", t.Format("1"), -1) res = strings.Replace(res, "DD", t.Format("02"), -1) res = strings.Replace(res, "D", t.Format("2"), -1) res = strings.Replace(res, "YYYY", t.Format("2006"), -1) res = strings.Replace(res, "YY", t.Format("06"), -1) res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1) res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1) res = strings.Replace(res, "hh", t.Format("03"), -1) res = strings.Replace(res, "h", t.Format("3"), -1) res = strings.Replace(res, "mm", t.Format("04"), -1) res = strings.Replace(res, "m", t.Format("4"), -1) res = strings.Replace(res, "ss", t.Format("05"), -1) res = strings.Replace(res, "s", t.Format("5"), -1) return res }

延时函数:

func Sleep(ms time.Duration) { time.Sleep(ms*time.Millisecond); }

其它工具包

本小节列出其它的工具包。

日志

我一起纠结使用哪个日志库,在犹豫中花费很多时间,最后决定先用着一个版本,待到不合适时,再选择其它的。在接触 KubeEdge项目时,了解了 klog 库,考虑到其轻便,最终改造并使用。为了保持原样,其位置和名称均无变化。原始版本提供的主要接口函数如下:

Fatal Fatalf Fatalln Error Errorf Errorln Warning Warningf Warningln Exit Exitf Exitln

为了方便自己理解和使用,额外再添加:

Print Printf Println

这样就可以和 fmt 无缝切换了。

另外,考虑到不需要 pid,所以在输出提示符中去掉了 pid。输出格式如下:

[2020-10-20 21:47:29.411 busy.go:20] hello world

此提示符为笔者一直使用且已习惯。

详情可参考klog源码 。

补记: log4go功能强大,但似乎不能转义\n,会将其原样输出。

源码

本文所述工具包,大部分来自 此处github 的开源项目,在实践中不断优化并添加自己认为必要的工具函数。详细可参考笔者的 golang工程 。

最新回复(0)