• 29_Go基础(结构体)


      1 package main
      2 
      3 import (
      4     "encoding/json"
      5     "fmt"
      6     "unsafe"
      7 )
      8 
      9 // 1. 自定义变量类型
     10 type newInt int
     11 type myInt = int
     12 
     13 // 2. 定义结构体
     14 type person struct {
     15     name, city string
     16     age        int8
     17 }
     18 
     19 type student struct {
     20     name string
     21     age  int
     22 }
     23 
     24 type test struct {
     25     a int8
     26     b int8
     27     c int8
     28     d int8
     29 }
     30 
     31 func f1() {
     32     var a newInt
     33     var b myInt
     34     fmt.Printf("type a: %T\n", a) // type a: main.newInt
     35     fmt.Printf("type b: %T\n", b) // type b: int
     36 }
     37 
     38 func f2() {
     39     var p1 person
     40     p1.name = "张三"
     41     p1.city = "西安"
     42     p1.age = 16
     43     fmt.Printf("p1=%v\n", p1)  // p1={张三 西安 16}
     44     fmt.Printf("p1=%#v\n", p1) // p1=main.person{name:"张三", city:"西安", age:16}
     45 }
     46 
     47 // 3. 匿名结构体
     48 func f3() {
     49     var s1 struct {
     50         name string
     51         age  int8
     52     }
     53     s1.name = "李四"
     54     s1.age = 16
     55 
     56     fmt.Printf("s1=%v\n", s1)  // s1={李四 16}
     57     fmt.Printf("s1=%#v\n", s1) // s1=struct { name string; age int8 }{name:"李四", age:16}
     58 }
     59 
     60 // 4. 指针类型结构体
     61 func f4() {
     62     var p1 = new(person)       // 使用new关键字对结构体进行实例化,得到的是结构体的地址
     63     fmt.Printf("p1:%T\n", p1)  // p1:*main.person
     64     fmt.Printf("p1:%#v\n", p1) // p1:&main.person{name:"", city:"", age:0}
     65     p1.name = "小王子"
     66     p1.age = 28
     67     p1.city = "上海"             // 赋值 注意有语法糖 底层是 (*p1).city
     68     fmt.Printf("p1:%#v\n", p1) // p1:&main.person{name:"小王子", city:"上海", age:28}
     69 
     70     p2 := &person{}             // 使用&对结构体进行取地址操作相当于对该结构体类型进行了一次new实例化操作。
     71     fmt.Printf("p2: %T\n", p2)  // p2: *main.person
     72     fmt.Printf("p2: %#v\n", p2) // p2: &main.person{name:"", city:"", age:0}
     73 
     74 }
     75 
     76 // 5. 结构体初始化
     77 func f5() {
     78     // 没有初始化的结构体,其成员变量都是对应其类型的零值
     79     var p1 person
     80     fmt.Printf("p1:%T\n", p1)  // p1:main.person
     81     fmt.Printf("p1:%#v\n", p1) // p1:main.person{name:"", city:"", age:0}
     82 
     83     // 使用键值对初始化 可部分初始化,一部分默认零值
     84     p2 := person{
     85         name: "王五",
     86         age:  17,
     87     }
     88     fmt.Printf("p2:%#v\n", p2) // p2:main.person{name:"王五", city:"", age:17}
     89 
     90     // 结构体指针键值对初始化
     91     p3 := &person{
     92         name: "赵六",
     93     }
     94     fmt.Printf("p3:%#v\n", p3) // p3:&main.person{name:"赵六", city:"", age:0}
     95 
     96     // 使用值列表初始化 字段、顺序必须一一对应
     97     p4 := &person{
     98         "隔壁老王",
     99         "隔壁",
    100         35,
    101     }
    102     fmt.Printf("p4:%#v\n", p4) // p4:&main.person{name:"隔壁老王", city:"隔壁", age:35}
    103 
    104 }
    105 
    106 // 6. 结构体内存布局 结构体占用一块连续的内存。
    107 func f6() {
    108     p := test{
    109         1, 2, 3, 4,
    110     }
    111     fmt.Printf("type of p: %T\n", p) // type of p: main.test
    112     fmt.Printf("val of p: %#v\n", p) // val of p: main.test{a:1, b:2, c:3, d:4}
    113     fmt.Printf("p.a: %v\n", &p.a)    // p.a: 0xc000014190
    114     fmt.Printf("p.b: %v\n", &p.b)    // p.a: 0xc000014191
    115     fmt.Printf("p.c: %p\n", &p.c)    // p.a: 0xc000014192
    116     fmt.Printf("p.d: %p\n", &p.d)    // p.a: 0xc000014193
    117 
    118     // 传值 与 传地址
    119     p1 := &test{
    120         5, 6, 7, 8,
    121     }
    122     fmt.Printf("type of p1: %T\n", p1) // type of p1: *main.test
    123     fmt.Printf("val of p1: %#v\n", p1) // val of p1: &main.test{a:5, b:6, c:7, d:8}
    124     fmt.Printf("p1.a: %#v\n", &p1.a)   // p1.a: (*int8)(0xc0000141c0)
    125     fmt.Printf("p1.b: %#v\n", &p1.b)   // p1.b: (*int8)(0xc0000141c1)
    126     fmt.Printf("p1.c: %#p\n", &p1.c)   // p1.c: c0000141c2
    127     fmt.Printf("p1.d: %#p\n", &p1.d)   // p1.d: c0000141c3   %p 前加 # 没用
    128 }
    129 
    130 // 7. 空结构体 不占空间
    131 func f7() {
    132     var v struct{}
    133     var s = []int{1, 2, 3}
    134     fmt.Println(s)                // [1 2 3]
    135     fmt.Println(unsafe.Sizeof(v)) // 0
    136     fmt.Println(unsafe.Sizeof(s)) // 24
    137 }
    138 
    139 // 8. 面试题
    140 func f8() {
    141     m := make(map[string]*student)
    142     stus := []student{
    143         {name: "小王子", age: 18},
    144         {name: "娜扎", age: 23},
    145         {name: "大王八", age: 9000},
    146     }
    147 
    148     fmt.Println(stus)      // [{小王子 18} {娜扎 23} {大王八 9000}]
    149     fmt.Printf("%#v\n", m) // map[string]*main.student{}
    150     for _, stu := range stus {
    151         fmt.Println(stu.name, &stu) // &{小王子 18   &{娜扎 23}  &{大王八 9000}
    152         fmt.Printf("%p\n", &stu)    // 0xc0001120c0  地址是不变的
    153         m[stu.name] = &stu
    154     }
    155 
    156     fmt.Println(m) // map[大王八:0xc0000040d8 娜扎:0xc0000040d8 小王子:0xc0000040d8]
    157     for k, v := range m {
    158         fmt.Println(k, "=>", v.name)
    159         // 小王子 => 大王八
    160         // 娜扎 => 大王八
    161         // 大王八 => 大王八
    162 
    163     }
    164 }
    165 
    166 // 9. 构造函数
    167 func newPerson(name, city string, age int8) *person {
    168     return &person{
    169         name: name,
    170         city: city,
    171         age:  age,
    172     }
    173 }
    174 
    175 func f9() {
    176     var p1 = newPerson("张三", "西安", 16)
    177     fmt.Printf("%#v\n", p1) // &main.person{name:"张三", city:"西安", age:16}
    178 }
    179 
    180 // 10. 方法和接收者  方法属于特定的类型
    181 func (p person) Dream() {
    182     fmt.Printf("%s的梦想是学号Go语言\n", p.name)
    183     p.age = 100                // 值类型的接收者,修改的是副本
    184     fmt.Printf("修改副本:%v\n", p) // 修改副本:{小明 西安 100}
    185 }
    186 
    187 func (p *person) setAge(newAge int8) {
    188     p.age = newAge // 方法类型的接收者,修改原值
    189 }
    190 
    191 func f10() {
    192     var p1 = newPerson("小明", "西安", 10)
    193     p1.Dream()
    194     fmt.Printf("Dream后:%v\n", p1) // Dream后:&{小明 西安 10}
    195     p1.setAge(11)
    196     fmt.Printf("setAge后:%v\n", p1) // setAge后:&{小明 西安 11}
    197 }
    198 
    199 // 11. 结构体匿名字段
    200 type anonymousPerson struct {
    201     string
    202     int8
    203 }
    204 
    205 func f11() {
    206     p1 := anonymousPerson{
    207         "小王子",
    208         18,
    209     }
    210     fmt.Printf("%#v\n", p1) // main.anonymousPerson{string:"小王子", int8:18}
    211     // 匿名字段的说法并不代表没有字段名,而是默认会采用类型名作为字段名,
    212     // 结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。
    213 }
    214 
    215 // 12. 嵌套结构体
    216 type Address struct {
    217     Provice string
    218     City    string
    219 }
    220 
    221 type User struct {
    222     Name    string
    223     Age     int8
    224     Address Address
    225 }
    226 
    227 type User1 struct {
    228     Name    string
    229     Age     int8
    230     Address // 匿名字段
    231 }
    232 
    233 func f12() {
    234     p1 := User{
    235         Name: "隔壁老王",
    236         Age:  30,
    237         Address: Address{
    238             Provice: "陕西",
    239             City:    "西安",
    240         },
    241     }
    242     fmt.Println(p1)         // {隔壁老王 30 {陕西 西安}}
    243     fmt.Printf("%#v\n", p1) // main.User{Name:"隔壁老王", Age:30, Address:main.Address{Provice:"陕西", City:"西安"}}
    244 
    245     var p2 User1
    246     p2.Name = "小红"
    247     p2.Age = 28
    248     p2.Address.Provice = "陕西" // 匿名字段默认使用类型名作为字段名
    249     p2.City = "商洛"            // 匿名字段可以省略, 直接用 p2
    250     fmt.Println(p2)           // {小红 28 {陕西 西安}}
    251     fmt.Printf("%#v\n", p2)   // main.User1{Name:"小红", Age:28, Address:main.Address{Provice:"陕西", City:"商洛"}}
    252 }
    253 
    254 // 13. 结构体的继承
    255 type Animal struct {
    256     name string
    257 }
    258 
    259 func (a *Animal) Move() {
    260     fmt.Printf("%s 会跑\n", a.name)
    261 }
    262 
    263 type Dog struct {
    264     feet    int
    265     *Animal // 通过结构体匿名字段实现继承 (字段,方法)
    266 }
    267 
    268 func (d *Dog) Bark() {
    269     // 自己的方法
    270     fmt.Printf("%s 会汪汪汪的叫\n", d.name)
    271 }
    272 
    273 func f13() {
    274     d := &Dog{
    275         feet: 4,
    276         Animal: &Animal{
    277             name: "吉娃娃",
    278         },
    279     }
    280     d.Move() // 吉娃娃 会跑
    281     d.Bark() // 吉娃娃 会汪汪汪的叫
    282 }
    283 
    284 // 14. 结构体与JSON序列化
    285 type Student1 struct {
    286     ID   int
    287     Name string
    288 }
    289 
    290 type Class struct {
    291     Name     string
    292     Students []*Student1
    293 }
    294 
    295 func f14() {
    296     cls := &Class{ // 班级初始化
    297         Name:     "三年级一班",
    298         Students: make([]*Student1, 0, 200), // 学生初始化
    299     }
    300 
    301     for i := 0; i < 3; i++ {
    302         stu := &Student1{
    303             ID:   i,
    304             Name: fmt.Sprintf("stu%02d", i),
    305         }
    306         cls.Students = append(cls.Students, stu)
    307     }
    308 
    309     // JSON序列化
    310     data, err := json.Marshal(cls)
    311     if err != nil {
    312         fmt.Println("json序列化失败")
    313         return
    314     }
    315     fmt.Printf("json: %s\n\n", data)
    316     /*
    317         json: {
    318             "Name":"三年级一班",
    319             "Students":[
    320                 {"ID":0,"Name":"stu00"},
    321                 {"ID":1,"Name":"stu01"},
    322                 {"ID":2,"Name":"stu02"}
    323             ]
    324         }
    325     */
    326 
    327     // JSON 反序列化
    328     str := `{"Name":"三年级一班","Students":[{"ID":0,"Name":"stu00"},{"ID":1,"Name":"stu01"},{"ID":2,"Name":"stu02"}]}`
    329     cls1 := &Class{}
    330     err = json.Unmarshal([]byte(str), cls1)
    331     if err != nil {
    332         fmt.Println("jsonF反序列化失败")
    333         return
    334     }
    335     fmt.Printf("%#v\n", cls1)
    336     /*
    337         &main.Class{
    338             Name:"三年级一班",
    339             Students:[]*main.Student1{
    340                 (*main.Student1)(0xc0000a61f8),
    341                 (*main.Student1)(0xc0000a6210),
    342                 (*main.Student1)(0xc0000a6228)
    343             }
    344         }
    345     */
    346 
    347 }
    348 
    349 // 15. 注意 因为slice和map这两种数据类型都包含了指向底层数据的指针,因此我们在需要复制它们时要特别注意
    350 type Person2 struct {
    351     name   string
    352     age    int8
    353     dreams []string
    354 }
    355 
    356 // 错误的做法
    357 func (p *Person2) SetDreams(dreams []string) {
    358     p.dreams = dreams
    359 }
    360 
    361 // 正确的做法
    362 func (p *Person2) SetDreams1(dreams []string) {
    363     p.dreams = make([]string, len(dreams))
    364     copy(p.dreams, dreams)
    365 }
    366 
    367 func f15() {
    368     p1 := Person2{name: "小王子", age: 18}
    369     data := []string{"吃饭", "睡觉", "打豆豆"}
    370     p1.SetDreams(data) // p1.SetDreams1(data)
    371 
    372     // 你真的想要修改 p1.dreams 吗?
    373     data[1] = "不睡觉"
    374     fmt.Println(p1.dreams) // [吃饭 不睡觉 打豆豆] 并没有 setDreams,但 dreams 却改了
    375 }
    376 
    377 func main() {
    378     // f1()
    379     // f2()
    380     // f3()
    381     // f4()
    382     // f5()
    383     // f6()
    384     // f7()
    385     // f8()
    386     // f9()
    387     // f10()
    388     // f11()
    389     // f12()
    390     // f13()
    391     // f14()
    392     f15()
    393 }
  • 相关阅读:
    npm安装Vue及配置
    Node.js安装
    代码优化总结
    Java 读取文件指定行数的数据
    Navicat Premium 15 v15.0.17 数据库开发工具 安装激活详解
    发现了一个关于 gin 1.3.0 框架的 bug
    802.1X 账号密码+设备信息双重认证
    Vue项目入门(一)
    WPF登录界面
    使用“user32.dll”控制窗体
  • 原文地址:https://www.cnblogs.com/luwei0915/p/15500334.html
Copyright © 2020-2023  润新知