• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
正在输入>
博客园    首页    新随笔    联系   管理    订阅  订阅

GO学习笔记(5)

五. 结构体

  5.1. 结构体定义和初始化

func structDefine() {
    // 关键字: type

    // 1.自定义类型, 具有int相同的特性, 但类型是自定义类型: main.myInt, 表示main包下的myInt类型
    type myInt int
    var a myInt
    fmt.Printf("%T \n", a) // main.myInt

    // 2. 类型别名, 本质上就是int类型
    type aint = int
    var b aint
    fmt.Printf("%T \n", b) // int

    // 3. 结构体, 用 . 访问成员
    // 3.1 定义结构体
    type Stu struct {
        name  string
        age   int
        score float32
    }

    // 3.2 实例化
    stu1 := Stu{
        name:  "马大哈",
        age:   12,
        score: 10.5,
    }
    fmt.Printf("%v\n", stu1)  // {马大哈 12 10.5}
    fmt.Printf("%#v\n", stu1) // main.Stu{name:"马大哈", age:12, score:10.5}

    // 3.3 匿名结构体
    var stu2 struct {
        name string
        age  int
    }
    stu2.name = "李二狗"
    stu2.age = 55
    fmt.Printf("%v\n", stu2)  // {李二狗 55}
    fmt.Printf("%#v\n", stu2) // struct { name string; age int }{name:"李二狗", age:55}

    // 3.4 结构体指针, 用new实例化
    p1 := new(Stu)
    fmt.Printf("%T \n", p1) // *main.Stu
    fmt.Printf("%#v\n", p1) // &main.Stu{name:"", age:0, score:0}
    p1.name = "丽丽"
    p1.age = 18
    p1.score = 99
    fmt.Printf("%#v\n", p1) // &main.Stu{name:"丽丽", age:18, score:99}

    // 3.5  取结构体的地址实例化
    p2 := &Stu{}
    fmt.Printf("%T \n", p2) // *main.Stu
    fmt.Printf("%#v\n", p2) // &main.Stu{name:"", age:0, score:0}

    // 3.6 结构体初始化
    // 3.6.1 声明完成后, 结构体其实已经实例化完成,所有的成员都是默认0值
    var p3 Stu
    fmt.Printf("%#v\n", p3) // main.Stu{name:"", age:0, score:0}
    // 3.6.2 键值对初始化
    p4 := Stu{
        name:  "二狗子",
        age:   10,
        score: 0,
    }
    fmt.Printf("%#v\n", p4) // main.Stu{name:"二狗子", age:10, score:0}
    // 3.6.3 结构体指针初始化
    p5 := &Stu{
        name:  "Go",
        age:   0,
        score: 0,
    }
    fmt.Printf("%#v\n", p5) // &main.Stu{name:"Go", age:0, score:0}
    // 3.6.4 值的列表初始化
    // 注意: 1.必须初始化结构体的所有字段
    //         2.初始值的填充顺序必须与字段在结构体中的声明顺序一致
    //       3.该方式不能和键值初始化方式混用
    p6 := Stu{
        "谁呀",
        18,
        20,
    }
    fmt.Printf("%#v\n", p6) // main.Stu{name:"谁呀", age:18, score:20}
}

  5.2. 小坑, 需要注意哈

func notice()  {
type student struct {
name string
age int
}
m := make(map[string]*student)
stus := []student{
{name: "张三", age: 18},
{name: "李四", age: 23},
{name: "王五", age: 28},
}

for i, stu := range stus {
fmt.Printf("%v, %p, %p \n",stu, &stu, &stus[i])
m[stu.name] = &stu
}
/** 输出: stu是 元素的拷贝, 并不是元素的引用
{张三 18}, 0xc000096440, 0xc0000d6000
{李四 23}, 0xc000096440, 0xc0000d6018
{王五 28}, 0xc000096440, 0xc0000d6030
*/
for k, v := range m {
fmt.Println(k, ":", v.name)
}
/** 输出:
张三 : 王五
李四 : 王五
王五 : 王五

原因: 因为for range创建的是每个元素的拷贝,而不是直接返回每个元素的引用
在for _, stu := range stus的时候,返回的stu其实并不是stus元素的引用,而是新的变量
*/
}

  5.3. 方法和接收者

// 方法和接收者
// 1. 接收者的类型可以是任何类型
// 2. 不能给别的包的类型定义方法
type Animal struct {
    name string
    age  int
}

// 接收者: 方法就只属于Animal这个类型,其他类型无法调用
func (a Animal) info() {
    fmt.Println(a.name, a.age)
}

// 修改成员的时候, 接收者类型必须是引用类型
func (a *Animal) setAge(age int) {
    a.age = age
}
func (a Animal) setAge1(age int) {
    a.age = age
}

type myInt int
func (m myInt) printInfo() {
    fmt.Println("我是", m)
}

// 以下这些情况,接收者类型应该使用引用类型:
//    1.需要修改接收者中的值
//    2.接收者是拷贝代价比较大的大对象
//    3.保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。
func method() {
    a := Animal{
        name: "阿猫",
        age:  1,
    }
    a.info() // 阿猫 1
    a.setAge(20)
    a.info() // 阿猫 20
    a.setAge1(18)
    a.info() // // 阿猫 20

    // 为自定义类型定义了方法
    var b myInt = 10
    b.printInfo() // 我是 10
}

  5.4. JSON序列化

func json2struct()  {
// 只要是可导出成员(变量首字母大写), 都可以转成json
type Employee struct {
Name string
Salary float32
seniority int
}
a := &Employee{
Name:"渣渣灰",
Salary:12.8,
seniority:2,
}
data, _ := json.Marshal(a)
fmt.Printf("%s\n",data) // {"Name":"渣渣灰","Salary":12.8}

// 反序列, 变量为私有(首字母小写), 无法被识别
s := `{"Name":"渣渣渣","Salary":12.5, "seniority":3}`
c := &Employee{}
json.Unmarshal([]byte(s), c)
fmt.Printf("%#v\n", c) // &main.Employee{Name:"渣渣渣", Salary:12.5, seniority:0}
}

  5.5. 结构体标签

func tag() {
    // 结构体标签: Tag在结构体字段的后方定义, 由一对反引号包裹起来, 键与值使用冒号分隔,值用双引号括起来
    type Employee struct {
        Name      string `json:"name"`
        Salary    float32
        seniority int
    }
    a := &Employee{
        Name:      "渣渣灰",
        Salary:    12.8,
        seniority: 2,
    }
    data, _ := json.Marshal(a)
    // 有标签的成员,在json中的字段名为标签的值
    fmt.Printf("%s\n", data) // {"name":"渣渣灰","Salary":12.8}


    // 反序列的时候, 有标签的成员可以识别标签值, 也可以识别成员本身的名字
    s1 := `{"Name":"渣渣","Salary":1.5, "seniority":1}`
    s2 := `{"name":"渣渣渣","Salary":12.5, "seniority":3}`
    c1 := &Employee{}
    c2 := &Employee{}
    json.Unmarshal([]byte(s1), c1)
    json.Unmarshal([]byte(s2), c2)
    fmt.Printf("%#v\n", c1) // &main.Employee{Name:"渣渣", Salary:1.5, seniority:0}
    fmt.Printf("%#v\n", c2) // &main.Employee{Name:"渣渣渣", Salary:12.5, seniority:0}
}

 

posted @ 2020-08-07 15:59  正在输入>  阅读(144)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3