Golang []byte与string转换的一个误区
https://www.oyohyee.com/post/Note/golang_byte_to_string/
2019-08-10 23:46:31
610
在实现[]byte转换string的过程中,发现了一个很容易理解错误的地方。
注意:这里要区分
0
,'\0'
,'0'
的区别。其中前两者等价,是内存中实际的值。而'0'
是显示的值,其在内存中实际是48
,也即0x30
在C语言中,字符串的结尾是'\0'
,也即字节为0
的字符。
#include <stdio.h>
#include <string.h> int main() {
char s[] = {'a', 'b', 'c', '\0', '\0', 'd'};
printf("%d %d %s\n", strlen(s), sizeof(s), s); return 0;
}
这个程序输出的内容是3 6 abc
而在Go语言中,字符串仅仅把对应字节为0
的字符认为是空字符,不显示但是仍然占用长度。
package main import (
"fmt"
) func main() {
b := []byte{'a', 'b', 'c', 0, 0, 'd'}
s := string(b)
fmt.Printf("%d %s %s\n", len(s), s, b)
}
这个程序输出的内容是6 abcd abcd
0
在C语言以及Go语言不同的表现在大部分情况下不会造成问题,但是当使用io.Reader(b []byte)
时,如果传入的字节数组b
本身长度大于reader可读到的长度,则会导致末尾被0
补齐。当直接使用string(b)
强制类型转换时会导致显示上看似无问题,但是实际上字符串并不相同。
要解决这个问题需要对[]byte
和string
的转换过程进行一个封装。
这里实现了针对两种情况的解决方案,前者是遇到0
就结束转换,后者则是忽略所有的0
并将剩余部分拼接
// String 将 `[]byte` 转换为 `string`
func String(b []byte) string {
for idx, c := range b {
if c == 0 {
return string(b[:idx])
}
}
return string(b)
} // StringWithoutZero 将 `[]byte` 转换为 `string`
func StringWithoutZero(b []byte) string {
s := make([]rune, len(b))
offset := 0
for i, c := range b {
if c == 0 {
offset++
} else {
s[i-offset] = rune(c)
}
}
return string(s[:len(b)-offset-1])
}