日常编程中类型转化不可避免,将其他数据类型转化为字符串类型特别常见。使用fmt.Sprintf
确实相当方便,因为接收的参数是interface{}
,所以什么类型都能通过该函数做转换。其底层使用了反射
来实现该功能,正因如此,在转化效率上就比较低效。
到底转化效率差距有多大,可以通过函数对比来实现。
测试代码
func TestFmtStrconv(t *testing.T) {
loopTotalNum := 20000
// 对比 fmt.Sprintf 和 strconv.FormatInt
start := time.Now()
for i := 0; i < loopTotalNum; i++ {
fmt.Sprintf("%d", i)
}
fmt.Println("fmt elapsed for int: ", time.Since(start))
start = time.Now()
for i := 0; i < loopTotalNum; i++ {
strconv.FormatInt(int64(i), 10)
}
fmt.Println("strconv elapsed for int: ", time.Since(start))
// 对比 fmt.Sprintf 和 strconv.FormatInt
start = time.Now()
for i := 0; i < loopTotalNum; i++ {
fmt.Sprintf("%f", 2.0)
}
fmt.Println("fmt elapsed for double: ", time.Since(start))
start = time.Now()
for i := 0; i < loopTotalNum; i++ {
strconv.FormatFloat(2.0, 'e', 2, 32)
}
fmt.Println("strconv elapsed for double: ", time.Since(start))
hexBytes := []byte("hello world")
start = time.Now()
for i := 0; i < loopTotalNum; i++ {
fmt.Sprintf("%x", hexBytes)
}
fmt.Println("fmt elapsed for hex: ", time.Since(start))
start = time.Now()
for i := 0; i < loopTotalNum; i++ {
hex.EncodeToString(hexBytes)
}
fmt.Println("strconv elapsed for hex: ", time.Since(start))
}
测试数据
=== RUN TestFmtStrconv
fmt elapsed for int: 1.823708ms
strconv elapsed for int: 589.985µs
fmt elapsed for double: 4.610381ms
strconv elapsed for double: 2.074034ms
fmt elapsed for hex: 2.701938ms
strconv elapsed for hex: 916.221µs
--- PASS: TestFmtStrconv (0.01s)
PASS
ok go-demo/x-demo 0.020s
测试结论
- 整形
strconv.FormatInt
执行时间为fmt.Sprintf
的三分之一
。
strconv.Itoa
是对strconv.FormatInt
做了封装,转化时间相当。
整型转化为字符串使用两种方式,
int
:使用strconv.Itoa
。
int32
,int64
,int8
等:使用strconv.FormatInt
。
- 浮点型
strconv.FormatFloat
执行时间为fmt.Sprintf
的二分之一
。
- 16进制
hex.EncodeToString
执行时间为fmt.Sprintf
的三分之一
。
总之,数据转化不建议使用fmt.Sprintf
。