Go:struct
一、使用方式
方式3和方式4返回的是:结构体指针,编译器底层对 p.Name 做了转化 *(p).Name,方便程序员使用。
type Person struct { Name string Age int } func main() { // 方式1 var p Person fmt.Println(p) // { 0} var p1 = Person{} p1.Name = "a" p1.Age = 1 fmt.Println(p1) // {a 1} // 方式2 var p2 = Person{"b", 2} var p3 = Person{ Name: "b", Age: 2, } p4 := Person{"b", 2} p5 := Person{ Name: "b", Age: 2, } fmt.Println(p2, p3, p4, p5) // {b 2} {b 2} {b 2} {b 2} // 方式3 var p6 = new(Person) // var p6 *Person = new(Person) /* go的设计者,为了程序员的使用方便,底层会对 p6.Name = "c"进行处理, 相当于*(p6).Name = "c" */ p6.Name = "c" // *(p6).Name = "c" p6.Age = 3 // *(p6).Age = 3 fmt.Println(p6) // &{c 3} fmt.Println(*p6) // {c 3} // 方式4(同方式3) var p7 = &Person{} p7.Name = "d" p7.Age = 4 fmt.Println(p7, *p7) // &{d 4} {d 4} var p8 = &Person{"e", 5} fmt.Println(p8, *p8) // &{e 5} {e 5} p9 := &Person{} p9.Name = "f" p9.Age = 6 fmt.Println(p9, *p9) // &{f 6} {f 6} p10 := &Person{"g", 7} fmt.Println(p10, *p10) // &{g 7} {g 7} }
二、结构体中的指针、slice、map的默认值都是nil,即还没分配空间
type Person struct { Name string Age int Score [3]float64 ptr *int s []int m map[string]string } func main() { var p Person fmt.Println(p) // { 0 [0 0 0] <nil> [] map[]} if p.ptr == nil { fmt.Println("true") // true } if p.s == nil { fmt.Println("true") // true } if p.m == nil { fmt.Println("true") // true } // 使用slice和map时,一定要make!!! p.s = make([]int, 2) p.s[0] = 88 fmt.Println(p.s) // [88 0] p.m = make(map[string]string, 2) p.m["key"] = "value" fmt.Println(p.m) // map[key:value] }
三、结构体的tag
struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化。
package main import ( "encoding/json" "fmt" ) type Person struct{ Name string `json:"name"` // `json:"name"`就是结构体tag Age int // `json:"age"` ,没有写tag,序列化后则为大写字母,如果字段为小写,其他包又不可见 } func main() { person := Person{"佩奇", 18} jsonStr, err := json.Marshal(person) if err != nil { fmt.Println(err) } else { fmt.Println(string(jsonStr)) // {"name":"佩奇","Age":18} } }
四、其他
结构体的所有字段在内存中是连续的。
type Student struct { A int B int C int } func main() { s := Student{1, 20, 300} fmt.Println(&s.A) // 0xc00000e3a0 fmt.Println(&s.B) // 0xc00000e3a8 fmt.Println(&s.C) // 0xc00000e3b0 }
结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数、类型)。
type A struct { Name string } type B struct { Name string } type C A // 结构体进行type重新定义(相当于取别名) func main() { var a A var b B a = A(b) // 可以强转,但有前提 var c C c = C(a) // 可以强转 fmt.Println(a, b, c) }