上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
5.5 结构
结构体将多个字段序列打包成一个复合类型。
- 直属字段名必须唯一。
- 支持自身指针类型成员。
- 可用
_
忽略字段名。
- 支持匿名结构和空结构。
- 支持匿名嵌入其他类型。
- 支持为字段添加标签。
- 仅所有字段全部支持,才可做相等操作。
- 可用指针选择字段,但不支持多级指针。
- 字段的名称、类型、标签及排列顺序属类型组成部分。
- 除对齐外,编译器不会优化或调整布局。
顺序初始化,必须包含全部字段值。而命名初始化,不用全部字段,也无关顺序。
建议使用命名方式,即便后续新增字段或调整排列顺序也不受影响。
type node struct { id int value string next *node // 自身指针类型。 } func main() { // 顺序提供所有字段值,或全部忽略。 // n := node{ 1, "a" } // ~~~~~~~~~~~~~~ too few values in struct literal // 按字段名初始化。 n := node{ id : 2, value: "abc", // 注意结尾逗号 !!! } }
func main() { // 匿名结构 user := struct { id int name string }{ id : 1, name: "user1", } fmt.Printf("%+v\n", user) // -------------------- var color struct { r int g int b int } color.r = 1 color.g = 2 color.b = 3 fmt.Printf("%+v\n", color) } // {id:1 name:user1} // {r:1 g:2 b:3}
func main() { type file struct { name string attr struct { owner int perm int } } f := file{ name: "test.dat", // 因缺少类型标签,无法直接初始化。 // attr: { // owner: 1, // perm: 0755, // }, // ~~~~~~~~~ missing type in composite literal } f.attr.owner = 1 f.attr.perm = 0755 fmt.Println(f) }
相等操作限制:
- 全部字段支持。
- 内存布局相同,但类型不同,不能比较。
- 布局相同(含字段名、标签等)的匿名结构视为同一类型。
func main() { type data struct { x int y map[string]int } d1 := data{ x: 100 } d2 := data{ x: 100 } // _ = d1 == d2 // ~~~~~~~~ invalid: struct containing map cannot be compared }
func main() { // 类型不同! type data1 struct { x int } type data2 struct { x int } d1 := data1{ x: 100 } d2 := data2{ x: 100 } // _ = d1 == d2 // ~~~~~~~~ invalid: mismatched types data1 and data2 }
func main() { // 匿名结构类型相同的前提是 // 字段名、字段类型、标签和排列顺序都相同。 d1 := struct { x int s string }{ 100, "abc" } var d2 struct { x int s string } d2.x = 100 d2.s = "abc" println(d1 == d2) // true }
不能以多级指针访问字段成员。
func main() { type user struct { name string age int } // 直接返回指针。 p := &user{ name: "u1", age: 20, } p.name = "u2" p.age++ // 二级指针。 p2 := &p // p2.age++ // ~~~~~~ p2.age undefined (type **user has no field or method age) }
空结构
空结构( struct{}
)是指没有字段的结构类型,常用于值可被忽略的场合。
无论是其自身,还是作为元素类型,其长度都为零,但这不影响作为实体存在。
func main() { var a struct{} var b [1000]struct{} s := b[:] println(unsafe.Sizeof(a), unsafe.Sizeof(b)) // 0, 0 println(len(s), cap(s)) // 1000, 1000 }
func main() { // 结束通知,值无关紧要。 done := make(chan struct{}) go func(){ time.Sleep(time.Second) close(done) }() <- done }
func main() { nul := struct{}{} users := make(map[int]struct{}) for i := 0; i < 100; i++ { users[i] = nul } // 利用字典随机选人,值不需要。 for k, _ := range users { println(k) break } }
标签
标签(tag)不是注释,而是对字段进行描述的元数据。
- 不是数据成员,却是类型的组成部分。
- 内存布局相同,允许显式类型转换。
func main() { type user struct { id int `id` } type user2 struct { id int `uid` // !!!! } u1 := user{1} u2 := user2{2} // 类型不同。 // _ = u1 == u2 // ~~~~~~~~ mismatched types user and user2 // 内存布局相同,支持转换。 u1 = user(u2) fmt.Println(u1) }
运行期,可用反射获取标签信息。常被用作格式校验,数据库关系映射等。
package main import ( "fmt" "reflect" ) func main() { type User struct { id int `field:"uid" type:"integer"` name string `field:"name" type:"text"` } t := reflect.TypeOf(User{}) for i := 0; i < t.NumField(); i++ { f := t.Field(i) fmt.Println(f.Name, f.Tag.Get("field"), f.Tag.Get("type")) } } // id: uid integer // name: name text
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论