结构体由一系列被称为字段的元素组成。每个字段由名称和类型组成,字段名称可以被显示命名,也可以是匿名的。在声明结构体类型时,字段名称必须唯一,可使用"_"补位,支持使用自身指针类型成员。字段名和排列顺序都属于结构体类型的组成部分,因为编译器会对结构体中的字段做对齐优化,比如:
结构体声明:
typePersonstruct{ namestring ageint _int }
结构体初始化:
1. 可按顺序初始化全部字段
2. 使用命名方式初始化指定字段
typePersonstruct{ namestring ageint } { p:=Person{ "Tom",20,} /*//初始化排列顺序不能错乱 p:=Person{ 20,"Tom",} */ /* p:=Person{ "Tom"}//toofewvaluesinstructinitializer */ p1:=Person{ name:"Tom",age:20,} p2:=Person{ name:"unknown",} }
PS:因为命名初始化不受结构体扩展和字段顺序变化的影响,在日常开发中,建议使用命名初始化。
可以在函数体中直接定义匿名结构类型变量或用作字段类型,比如:
{ u:=struct{//直接定义匿名结构体变量 namestring ageint }{ "Tom",} typefilestruct{ namestring attrstruct{//定义命名嵌入结构类型字段 sizeint permint } } f:=file{ name:"passwd",attr:{//missingtypeincompositeliteral size:1,perm:1,},} f.attr.size=1//ok f.attr.perm=1 }
结构体比较:
只有在所有字段类型全部支持相等运算符时,才可以做相等操作,比如:
typedatastruct{ xint //ymap[int]int y[]int } funcmain(){ d1:=data{x:1} d2:=data{x:2} fmt.Println(d1==d2)//(structcontaining[]intcannotbecompared) }
可以使用结构体指针直接操作结构体,但是不能是多级指针,比如:
{ typePersonstruct{ namestring ageint } p:=&Person{ "Li",} fmt.Println(p) p.name="Tom" p.age=10 fmt.Println(p) p2:=&p *p2.name="Tom2"//p2.nameundefined(type**Personhasnofieldormethodname) //(*p2).name="Tom2" fmt.Println(p2) }
空结构体:
空结构体(struct{}) 是指没有字段的结构体类型,无论是空结构体还是空结构体数组,其长度都为0,比如:
{ varastruct{} varb[100]struct{} println(unsafe.Sizeof(a),unsafe.Sizeof(b)) } 输出: 00
不影响对元素的操作,切片的内置子切片、长度和容量等属性依旧可以工作,比如:
{ varb[100]struct{} s:=b[:]//slice s[0]=struct{}{} s[1]=struct{}{} s[2]=struct{}{} fmt.Println(s[3],len(s),cap(s)) } 输出: {}100100
空结构体可以像其他结构体一样正常使用,空结构体也具有正常结构体的属性,但就日常应用来说,常用在通道元素类型做事件通知,
比如:
funchello(namestring,donechanstruct{}){ fmt.Println("hello",name) done<-struct{}{} } funcmain(){ done:=make(chanstruct{}) langs:=[]string{"Go","C","C++","Java","Perl","Python"} for_,l:=rangelangs{ gohello(l,done) } for_=rangelangs{ <-done } }
匿名字段:
匿名字段就是只有类型没有名字的字段(anonymous field),也称作嵌入类型或嵌入字段,比如:
typeattrstruct{ namestring ageint } typePersonstruct{ idint attr//结构体嵌入 } funcmain(){ p:=Person{ id:20,attr:attr{//显示初始化 name:"Tom",} p.name="kite"//可以直接读写匿名字段成员 p.attr.age=21//防止嵌入结构体成员与结构体成员重名 }
除接口指针和多级指针以外的任何命名类型都可以作为匿名字段,比如:
typedatastruct{ *int //int//duplicatefieldint string } funcinitData(){ x:=100 d:=data{ int:&x,//使用基本类型作为字段名 string:"Tom",} fmt.Printf("%#v\n",d) }
字段标签:
Go语言结构体提供了在运行时通过反射机制获取字段描述的元数据信息,尽管它不属于数据成员,但却是类型的组成的部分,日常开发中,常被用做格式校验和数据库关系映射等。比如:
typeattrstruct{ namestring`姓名` ageint`年龄` } typePersonstruct{ idint`身份证号码` attr`属性` } funcmain(){ p:=Person{ id:20,attr:attr{ name:"Tom",} v:=reflect.ValueOf(p) t:=v.Type() fori,n:=0,t.NumField();i<n;i++{ ifv.Field(i).Kind().String()=="struct"{ v1:=v.Field(i) t1:=v1.Type() forj,m:=0,t1.NumField();j<m;j++{ fmt.Printf("%s:%v\n",t1.Field(j).Tag,v1.Field(j)) } }else{ fmt.Printf("%s:%v\n",t.Field(i).Tag,v.Field(i).Kind()) } } } 输出: 身份证号码:int 姓名:Tom 年龄:20
内存布局:
不管结构体含有多少个字段,其内存总是一次性分配的,各字段在相邻的地址空间按定义顺序排列,编译器通常会对其做对齐处理,对齐通常以所有字段中最长基础类型宽度为准。对于字段是引用类型、字符串和指针的,结构内存中只包含基本数据,比如:
typePointstruct{ xint yint } typeValuestruct{ idint namestring data[]byte next*Value Point } funcmain(){ v:=Value{ id:1,name:"Tom",data:[]byte{1,2,3,4},next:nil,Point:Point{ x:100,y:200,} fmt.Printf("size:%d,align:%d\n",unsafe.Sizeof(v),unsafe.Alignof(v)) fmt.Printf("field\taddress\t\toffset\tsize\n") fmt.Printf("id\t%p\t%d\t%d\n",&v.id,unsafe.Offsetof(v.id),unsafe.Sizeof(v.id)) fmt.Printf("name\t%p\t%d\t%d\n",&v.name,unsafe.Offsetof(v.name),unsafe.Sizeof(v.name)) fmt.Printf("data\t%p\t%d\t%d\n",&v.data,unsafe.Offsetof(v.data),unsafe.Sizeof(v.data)) fmt.Printf("next\t%p\t%d\t%d\n",&v.next,unsafe.Offsetof(v.next),unsafe.Sizeof(v.next)) fmt.Printf("x\t%p\t%d\t%d\n",&v.Point.x,unsafe.Offsetof(v.Point.x),unsafe.Sizeof(v.Point.x)) fmt.Printf("y\t%p\t%d\t%d\n",&v.Point.y,unsafe.Offsetof(v.Point.y),unsafe.Sizeof(v.Point.y)) } 输出: size:72,align:8 field address offset size id 0xc4200140a0 0 8 name 0xc4200140a8 8 16 data 0xc4200140b8 24 24 next 0xc4200140d0 48 8 x 0xc4200140d8 0 8 y 0xc4200140e0 8 8 抽象布局: |-------16--------|------------24------------||------16-------| +---+--------+--------+--------+--------+--------+----+-------+-------+ |id|name.ptr|name.len|data.ptr|data.len|data.cap|next|point.x|point.y| +---+--------+--------+--------+--------+--------+----+-------+-------+ 081624324048566472
参照<<雨痕笔记&&GoLang官网>>
联系微信:675020908