zoukankan      html  css  js  c++  java
  • 面向对象之结构体2

    创建结构体变量和访问结构体字段

    1)方式1-直接声明

    案例演示:var person Person

    2)方式2-{}

    案例演示:var person Person = Person{}

    func main() {
      p2 := Person{}
      p2.Name = "tom"
      p2.Age = 18
      fmt.Println(p2)
    }


    3)方式3-&

    案例:var person *Person = new(Person)

    func main() {
      //方式3
      var p3 *Person = new(Person)
      //因为p3是一个指针,因此标准的给字段赋值的方式
      //(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"
      //原因是 go的设计者 为了程序员使用方便在底层会对 p3.Name = "smith" 进行处理
      //会给p3 加上 取值运算 (*p3).Name = "smith"
      (*p3).Name = "smith"
      p3.Name = "john"
      (*p3).Age = 30
      p3.Age = 100
      fmt.Println(*p3)
    }

    4)方式4-{}

    案例:var person *Person = &Person{}

    func main() {
      //方式4
      //下面的语句,也可以直接给字符赋值
      //var person *Person = &Person{"mary", 60}
      var person *Person = &Person{}
      //因为person 是一个指针,因此标准的访问字段的方法
      // (*person).Name = "scott"
      //go的设计者为了程序员使用方便,也可以直接写成 person.Name = "scott"
      //原因和上面一样,底层会做一些处理
      (*person).Name = "scott"
      person.Name = "scott~"
      (*person).Age = 88
      person.Age = 10
      fmt.Println(*person)
    }


    说明:
    (1) 第3种和第4种方式返回的是 结构体指针

    (2)结构体指针访问字段的标准方式应该是:(*结构体指针).字段名,比如:(*person).Name = "tom"

    (3) 但go做了一个简化,也支持 结构体指针.字段名,比如 person.Name = "tom"。更加符合程序员使用的习惯,go编译器底层对 person.Name 做了转化 (*person).Name

    结构体内存分配机制: 

    基本说明:

    变量总是存在内存中的,那么结构体变量在内存中究竟是怎么样存在的?

    看下面代码,并分析原因:

    下面一段代码,会输出什么信息:

    var p1 Person
    p1.Age = 10
    p1.Name = "小明"
    var p2 *Person = &p1

    fmt.Println((*p2).Age) //p1的Age 10
    fmt.Println(p2.Age) //p1的Age 10
    p2.Name = "tom~"
    fmt.Printf("p2.Name=%v p1.Name=%v ", p2.Name, p1.Name) //tom~
    fmt.Printf("p2.Name=%v p1.Name=%v ", (*p2).Name, p1.Name) //tom~

    输出的结果:

    在内存中的示意图:

    看下面的代码,并分析原因

    var p1 Person
    p1.Age =10
    p1.Name = "小明"
    var p2 *Person = &p1

    fmt.Println(*p2.Age) //能不能这样写?

    不对,因为.的运算符优先级比*高,所以先算它以后才会算*。 所以必须加括号(*p2).Age

    结构体使用细节:

    1)结构体的所有字段在内存中是连续的

    案例:

    type Rect struct {
      leftUp, rightDown Point
    }

    type Rect2 struct {
      leftUp, rightDown *Point
    }

    func main() {

      r1 := Rect{Point{1,2}, Point{3,4}}
      //r1有四个整数int,在内存中是连续分布
      //打印地址
      fmt.Printf("r1.leftUp.x 的地址=%p r1.leftUp.y 的地址=%p r1.rightDown.x 的地址=%p r1.rightDown.y 的地址=%p ",
      &r1.leftUp.x, &r1.leftUp.y, &r1.rightDown.x, &r1.rightDown.y)

      //r2有两个 *Point类型,这两个*Point类型的本身地址也是连续的
      //但是他们指向的地址不一定是连续的
      r2 := Rect2{&Point{10,20}, &Point{30,40}}

      //打印地址
      fmt.Printf("r2.leftUp 本身地址=%p r2.rightDown 本身地址=%p ",
      &r2.leftUp, &r2.rightDown)
      //他们指向的地址不一定是连续... 这个要看系统在运行时是怎么分配的
      fmt.Printf("r2.leftUp 指向地址=%p r2.rightDown 指向地址=%p ",
      r2.leftUp, r2.rightDown)
    }

    在内存中的示意图:

    2)结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)


    type A struct {
      Num int
    }

    type B struct {
      Num int
    }

    func main() {

      var a A
      var b B
      a = A(b) //可以转换,但是有要求,结构体的字段要完全一样(名字,个数和类型)
      fmt.Println(a,b)

    }


    3)结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转

    type Student struct {
      Name string
      Age int
    }

    type Stu Student

      func main() {
      var stu1 Student
      var stu2 Stu
      stu2 = stu1   //正确吗? 错误的,可以这样修改stu2 = Stu(stu1)
      fmt.Println(stu1,stu2)
    }

    type integer int

      func main() {
      var i integer = 10
      var j int = 20
      j = i   //正确吗? 错误的,因为golang认为integer是一种新的数据类型了,不能直接赋值,必须转换 j = int(i)
      fmt.Println(i,j)
    }


    4)struct 的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列号和反序列化。


    案例演示:

    package main
    import (
      "fmt"
      "encoding/json"
    )

    type Monster struct {
      Name string `json:"name"` // `json:"name"` 就是 struct tag
      Age int `json:"age"`
      Skill string `json:"skill"`
    }

    func main() {

      //1.创建一个Monster变量
      monster := Monster{"牛魔王", 500, "芭蕉扇~"}

      //2.将monster变量序列化为 json格式的字串
      // json.Marshal 函数中使用反射,这个讲解反射时再详细介绍
      jsonStr,err := json.Marshal(monster)
      if err != nil {
        fmt.Println("json 处理错误", err)
      }
      fmt.Println("jsonStr", string(jsonStr))
    }

  • 相关阅读:
    红楼梦 + 写入 MySQL + MongoDB
    糗事百科 + 微信自动回复
    验证码处理
    IP 代理池
    Ajax工作原理
    php做APP接口开发,接口的安全性
    http与https区别
    mysql 索引优化
    php+ajax+jquery实现jsonp跨域
    SpringBoot中文乱码解决方案
  • 原文地址:https://www.cnblogs.com/green-frog-2019/p/11408097.html
Copyright © 2011-2022 走看看