Golang中Int和binary.write的使用疑惑与困惑解析
Golang中Int和binary.write的使用疑惑与困惑解析 我认为我的做法可能不对。
据我理解,int 的大小没有明确定义,Go 似乎沿用了 C 的做法?无论如何,len(x) 返回值的类型大小没有定义,或者至少没有明确到让 binary.Write 不报错。
那么,正确的处理方式是改用 int64 吗?也就是说,如果我想将 len(x) 的返回值写入文件,我应该使用一个临时变量和更多的代码,对吗?这看起来不太优雅。
我不喜欢使用 JSON,不想依赖语言运行时或大量为我解析 JSON 的代码。
有没有更优雅的方法将数据序列化到缓冲区或文件中,而不必为 int 使用 int64?(不使用 golang 的 typeparams 分支?)
非工作代码 试图为我修复此问题:
编辑:哎呀,它确实能工作。我只是太吹毛求疵了,不想继续并修复其他地方的拼写错误。抱歉。
func save_var(file *os.File, x interface{}) {
switch t := x.(type) {
case int:
x = int64(x.(int))
_ = t
case custom_type_t:
x = int64(x.(custom_type_t))
_ = t
}
err := binary.Write(file, binary.LittleEndian, x)
if err != nil { panic(err) }
}
更优雅的版本:
func load_var(file *os.File, x interface{}) {
switch t := x.(type) {
case *int:
x = (*int64)(unsafe.Pointer((x.(*int))))
_ = t
case *custom_type_t:
x = (*int64)(unsafe.Pointer((x.(*custom_type_t))))
_ = t
}
err := binary.Read(file, binary.LittleEndian, x)
if err != nil { panic(err) }
}
如果 int64 与 len() 兼容,我会到处使用它,但我现在就像在 C++ 中决定/默认使用 int,然后在 STL 容器中遇到 size_t 一样困惑。
感谢阅读。
更多关于Golang中Int和binary.write的使用疑惑与困惑解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中Int和binary.write的使用疑惑与困惑解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理int类型与binary.Write/binary.Read时确实需要注意类型大小问题。你的理解是正确的:int的大小是平台相关的(32位系统上是32位,64位系统上是64位),而binary包要求明确大小的类型。
正确做法示例
1. 序列化时显式转换
package main
import (
"encoding/binary"
"os"
)
func saveLength(file *os.File, data []byte) error {
// 将int转换为固定大小的int64进行写入
length := int64(len(data))
if err := binary.Write(file, binary.LittleEndian, length); err != nil {
return err
}
// 写入实际数据
_, err := file.Write(data)
return err
}
func loadLength(file *os.File) ([]byte, error) {
var length int64
if err := binary.Read(file, binary.LittleEndian, &length); err != nil {
return nil, err
}
data := make([]byte, length)
_, err := file.Read(data)
return data, err
}
2. 使用类型安全的包装函数
package main
import (
"encoding/binary"
"io"
)
// 写入int值(自动转换为int64)
func WriteInt(w io.Writer, value int) error {
return binary.Write(w, binary.LittleEndian, int64(value))
}
// 读取int值
func ReadInt(r io.Reader) (int, error) {
var v int64
if err := binary.Read(r, binary.LittleEndian, &v); err != nil {
return 0, err
}
return int(v), nil
}
// 使用示例
func exampleUsage(w io.Writer, data []byte) error {
// 写入长度
if err := WriteInt(w, len(data)); err != nil {
return err
}
// 写入数据
_, err := w.Write(data)
return err
}
3. 处理自定义类型
package main
import (
"encoding/binary"
"fmt"
)
type CustomType int
func (c CustomType) MarshalBinary() ([]byte, error) {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, uint64(c))
return buf, nil
}
func (c *CustomType) UnmarshalBinary(data []byte) error {
if len(data) < 8 {
return fmt.Errorf("insufficient data")
}
*c = CustomType(binary.LittleEndian.Uint64(data))
return nil
}
// 使用binary.Write会自动调用MarshalBinary
func saveCustomType(w io.Writer, c CustomType) error {
return binary.Write(w, binary.LittleEndian, c)
}
关键点
-
不要使用unsafe.Pointer进行类型转换,这会导致未定义行为,特别是当
int和int64大小不同时(32位系统上)。 -
推荐始终使用显式转换:
// 写入时
length := int64(len(data))
binary.Write(writer, binary.LittleEndian, length)
// 读取时
var length int64
binary.Read(reader, binary.LittleEndian, &length)
dataLength := int(length)
-
对于需要序列化的长度字段,建议统一使用int64,这样可以确保跨平台兼容性。
-
如果你需要处理大量数据且关心性能,可以直接使用
binary.PutVarint和binary.ReadVarint来处理变长整数编码。
这种显式转换虽然看起来不够简洁,但确保了代码的清晰性和跨平台兼容性,这是Go语言设计哲学的一部分。

