我正在尝试编写一些base64
编码和解码字节切片的便捷包装函数。 (无法理解为什么在stdlib中没有方便地提供它。)
但是这段代码(在playground中):
func b64encode(b []byte) []byte {
encodedData := &bytes.Buffer{}
encoder := base64.NewEncoder(base64.URLEncoding, encodedData)
defer encoder.Close()
encoder.Write(b)
return encodedData.Bytes()
}
func b64decode(b []byte) ([]byte, error) {
dec := base64.NewDecoder(base64.URLEncoding, bytes.NewReader(b))
buf := &bytes.Buffer{}
_, err := io.Copy(buf, dec)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func main() {
b := []byte("hello")
e := b64encode(b)
d, err := b64decode(e)
if err != nil {
log.Fatalf("could not decode: %s", err)
}
fmt.Println(string(d))
}
当我尝试打印时,生成截断的输出:
hel
发生了什么事?
答案 0 :(得分:8)
当函数结束时执行defer。那是在评估了return语句之后。
以下作品:https://play.golang.org/p/sYn-W6fZh1
func b64encode(b []byte) []byte {
encodedData := &bytes.Buffer{}
encoder := base64.NewEncoder(base64.URLEncoding, encodedData)
encoder.Write(b)
encoder.Close()
return encodedData.Bytes()
}
话虽如此,如果真的全部都在内存中,你可以完全避免创建一个编码器。相反,你可以做类似的事情:
func b64encode(b []byte) []byte {
ret := make([]byte, base64.URLEncoding.EncodedLen(len(b)))
base64.URLEncoding.Encode(ret, b)
return ret
}
这样做的额外好处是它更有效率,因为它只需要分配一次。它还允许您不再忽略Write
和Close
方法中的错误。