0

0

Golang结构体如何定义 讲解字段标签与内存对齐

P粉602998670

P粉602998670

发布时间:2025-08-19 10:37:01

|

806人浏览过

|

来源于php中文网

原创

Golang结构体通过字段定义、标签和内存对齐组织数据;字段标签用于序列化控制,如json、xml等;内存对齐提升访问效率,可通过调整字段顺序优化布局减少填充;反射可读取标签实现通用处理逻辑。

golang结构体如何定义 讲解字段标签与内存对齐

Golang结构体定义的核心在于组织数据,字段标签用于反射和序列化,内存对齐则关乎性能。理解这三点,就能更好地使用Golang结构体。

结构体定义:

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
    City string `json:"city,omitempty"` //omitempty 忽略空值
}

字段标签:

字段标签是附加在结构体字段上的元数据,通常用于控制序列化和反序列化行为。例如,

json:"name"
指定了在JSON序列化时,该字段对应的键名为"name"。
omitempty
选项则表示如果字段为空值(如空字符串、0、nil),则在序列化时忽略该字段。

立即学习go语言免费学习笔记(深入)”;

内存对齐:

为了提高CPU的访问效率,编译器会对结构体字段进行内存对齐。这意味着每个字段的起始地址必须是其大小的倍数。例如,一个int32类型的字段的起始地址必须是4的倍数。编译器会在字段之间插入填充字节,以满足对齐要求。

为什么需要内存对齐?

内存对齐是为了优化CPU的读取效率。现代CPU通常以字(word)为单位读取内存,字的大小取决于CPU的架构(例如,32位CPU的字大小为4字节,64位CPU的字大小为8字节)。如果数据没有对齐,CPU可能需要多次读取才能获取完整的数据,这会降低性能。想象一下,你想从书架上拿一本书,如果书摆放整齐,你一次就能拿到;如果书摆放凌乱,你可能需要多次调整才能拿到。

如何查看结构体的内存布局?

可以使用

unsafe
包中的
Sizeof
Alignof
Offsetof
函数来查看结构体的内存布局。

package main

import (
    "fmt"
    "unsafe"
)

type User struct {
    A int8
    B int64
    C int16
}

func main() {
    var u User
    fmt.Println("Sizeof(User):", unsafe.Sizeof(u))
    fmt.Println("Alignof(User.A):", unsafe.Alignof(u.A))
    fmt.Println("Alignof(User.B):", unsafe.Alignof(u.B))
    fmt.Println("Alignof(User.C):", unsafe.Alignof(u.C))
    fmt.Println("Offsetof(User.A):", unsafe.Offsetof(u.A))
    fmt.Println("Offsetof(User.B):", unsafe.Offsetof(u.B))
    fmt.Println("Offsetof(User.C):", unsafe.Offsetof(u.C))
}

输出结果:

Sizeof(User): 24
Alignof(User.A): 1
Alignof(User.B): 8
Alignof(User.C): 2
Offsetof(User.A): 0
Offsetof(User.B): 8
Offsetof(User.C): 16

可以看到,

User
结构体的大小为24字节,尽管其字段的大小之和只有11字节。这是因为内存对齐导致了填充字节的插入。A占1字节,B需要8字节对齐,所以A后面填充7字节,B占8字节,C需要2字节对齐,所以B后面填充6字节,C占2字节,最后为了整体8字节对齐,C后面填充6字节。

麦艺画板(Max.art)
麦艺画板(Max.art)

AI工业设计平台,专注于汽车设计,线稿、渲染、3D建模全流程覆盖

下载

如何优化结构体的内存布局?

可以通过调整结构体字段的顺序来减少填充字节,从而减小结构体的大小。通常,将大小相同的字段放在一起,并将较大的字段放在前面,可以获得更好的内存布局。

例如,将上面的

User
结构体改为:

type UserOptimized struct {
    B int64
    C int16
    A int8
}

再次运行上面的代码,输出结果:

Sizeof(UserOptimized): 16
Alignof(UserOptimized.B): 8
Alignof(UserOptimized.C): 2
Alignof(UserOptimized.A): 1
Offsetof(UserOptimized.B): 0
Offsetof(UserOptimized.C): 8
Offsetof(UserOptimized.A): 10

可以看到,

UserOptimized
结构体的大小减小到了16字节。B占8字节,C占2字节,A占1字节,C后面填充5字节,最后整体8字节对齐,A后面填充5字节。

结构体标签的常见用法有哪些?

除了

json
标签外,还有许多其他的结构体标签,用于不同的目的。

  • xml
    :用于XML序列化和反序列化。
  • db
    :用于数据库操作,例如指定字段对应的数据库列名。
  • validate
    :用于数据验证,例如指定字段的取值范围。
  • mapstructure
    :用于将map转换为结构体。

例如:

type Product struct {
    ID    int    `db:"id"`
    Name  string `json:"name" validate:"required"`
    Price float64 `json:"price" xml:"price"`
}

在这个例子中,

ID
字段的
db
标签指定了对应的数据库列名为"id",
Name
字段的
json
标签指定了JSON键名为"name",并且
validate
标签指定该字段为必填项,
Price
字段的
xml
标签指定了XML标签名为"price"。

结构体标签和反射有什么关系?

结构体标签主要通过反射机制来读取和使用。

reflect
包提供了在运行时检查和操作类型信息的能力。可以使用
reflect.TypeOf
函数获取结构体的类型信息,然后使用
reflect.Type.Field
方法获取结构体字段的信息,包括字段的标签。

package main

import (
    "fmt"
    "reflect"
)

type Example struct {
    Field1 string `json:"field_1"`
    Field2 int    `json:"field_2" default:"10"`
}

func main() {
    t := reflect.TypeOf(Example{})
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        jsonTag := field.Tag.Get("json")
        defaultTag := field.Tag.Get("default")

        fmt.Printf("Field Name: %s\n", field.Name)
        fmt.Printf("JSON Tag: %s\n", jsonTag)
        fmt.Printf("Default Tag: %s\n", defaultTag)
        fmt.Println("---")
    }
}

输出结果:

Field Name: Field1
JSON Tag: field_1
Default Tag:
---
Field Name: Field2
JSON Tag: field_2
Default Tag: 10
---

通过反射,可以动态地获取结构体字段的标签,并根据标签的值来执行不同的操作。这使得我们可以编写通用的序列化、反序列化和验证代码。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

176

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

225

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

335

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

206

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

388

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

189

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

191

2025.06.17

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

150

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
AngularJS教程
AngularJS教程

共24课时 | 2.2万人学习

走进 ES6 新标准语法
走进 ES6 新标准语法

共15课时 | 1.5万人学习

PHP数字签名与加密解密
PHP数字签名与加密解密

共12课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号