补充斯蒂芬温伯格的回答:
那么,切片不适合的“规划内存的详细布局”或“帮助避免分配”的真实示例有哪些?
这里是一个“规划内存的详细布局”的例子。有许多文件格式。通常文件格式是这样的:它以"magic number" 开头,然后是一个信息性标题,其结构通常是固定的。此标头包含有关内容的信息,例如在图像文件的情况下,它包含图像大小(宽度、高度)、像素格式、使用的压缩、标头大小、图像数据偏移等信息(基本上描述了文件的其余部分以及如何解释/处理它)。
如果你想在 Go 中实现一种文件格式,一个简单方便的方法是创建一个包含格式头字段的struct。当你想读取这种格式的文件时,你可以使用binary.Read()方法将整个标题struct读入一个变量,同样当你想写入这种格式的文件时,你可以使用binary.Write()一步将完整的标头写入文件(或发送数据的任何位置)。
标头可能包含数十个或一百个字段,您仍然可以通过一个方法调用来读取/写入它。
现在您可以感觉到,如果您想一步完成所有操作,标头struct 的“内存布局”必须与文件中保存(或应该保存)的字节布局完全匹配。
数组在哪里出现?
许多文件格式通常很复杂,因为它们希望具有通用性,因此允许广泛的用途和功能。很多时候,您不想实现/处理格式支持的所有内容,因为您不关心(因为您只想提取一些信息),或者您不必这样做,因为您可以保证输入只会使用子集或固定格式(文件格式完全支持的许多情况)。
如果您有一个包含许多字段但只需要其中几个字段的标头规范,您会怎么做?您可以定义一个包含您需要的字段的结构,并且在字段之间您可以使用具有您不关心/不需要的字段大小的数组。这将确保您仍然可以通过一个函数调用读取整个标题,并且数组基本上将成为文件中未使用数据的占位符。如果您不使用数据,也可以使用 blank 标识符作为标头 struct 定义中的字段名称。
理论例子
举个简单的例子,让我们实现一个格式,其中魔法是“TGI”(Theoretical Go Image),并且标题包含如下字段:2 个保留字(每个 16 位)、1 个 dword 图像宽度、1 个 dword 图像高度,现在有 15 个“无关”双字,然后图像将时间保存为 8 字节,即自 1970 年 1 月 1 日 UTC 以来的纳秒。
这可以用这样的结构建模(不包括幻数):
type TGIHeader struct {
_ uint16 // Reserved
_ uint16 // Reserved
Width uint32
Height uint32
_ [15]uint32 // 15 "don't care" dwords
SaveTime int64
}
读取 TGI 文件并打印有用信息:
func ShowInfo(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
magic := make([]byte, 3)
if _, err = f.Read(magic); err != nil {
return err
}
if !bytes.Equal(magic, []byte("TGI")) {
return errors.New("Not a TGI file")
}
th := TGIHeader{}
if err = binary.Read(f, binary.LittleEndian, &th); err != nil {
return err
}
fmt.Printf("%s is a TGI file,\n\timage size: %dx%d\n\tsaved at: %v",
name, th.Width, th.Height, time.Unix(0, th.SaveTime))
return nil
}