前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言入门(六)结构体后续&指针

Go语言入门(六)结构体后续&指针

作者头像
alexhuiwang
发布2020-09-24 11:20:32
7930
发布2020-09-24 11:20:32
举报
文章被收录于专栏:运维博客运维博客

结构体后续&指针

指针

变量和内存地址

  • 每个变量都有内存地址,可以通过变量来操作对应的内存
代码语言:javascript
复制
func varMem() {
   var a int32 = 100
   fmt.Printf("addr %p\n",&a)
}

func pointMem() {
   var b int32
   b = 32
   var a *int32
   fmt.Printf("addr of a:%v\ntype of a %T\n",a,a)  //取出a的地址和类型
   a = &b
   fmt.Printf("a %d addr:%p\ntype of a:%T\nb %d addr %p\n",*a,&a,a,b,&b)
}

指针的定义与取值

  • &: 取地址
  • *: 取指针对应的值
  • 充分判断指针为nil的情况
代码语言:javascript
复制
func pointMem1()  {
   var a *int
   b := 200
   a = &b
   *a = 400
   fmt.Printf("a=%v,adda=%p,type a=%#T\nb=%v,addb=%p,type b=%#T\n",*a,a,a,b,&b)
}
func pointMem2()  {
   var a *int
   var b int = 100
   if a == nil {
      a = &b
   }
   fmt.Printf("addr a=%p,value a=%d\naddr b=%p,value b=%d\n",a,*a,&b,b)
}
  • 小例子

猜输出

代码语言:javascript
复制
func modify(a int) {
   a = 1000
}

func modify2(a *int) {
   fmt.Printf("address of a: %p\n",&a)
   *a = 1000
}

func main() {
   var b int = 100
   modify(b)
   fmt.Printf("b=%d\n",b)
   var p *int = &b
   fmt.Printf("address of p: %p\n",&p)
   modify2(&b)
   fmt.Printf("b=%d\n",b)
}

指针变量传参

  • 修改数组
代码语言:javascript
复制
func modifyArray(arr *[3]int) {
   //经过修改之后的arr,成了引用类型而不是值类型,因为其内存地址保持一致
   fmt.Printf("2. arr=%#v,address=%p\n",*arr,&arr)
   (*arr)[0] = 90
   fmt.Printf("3. arr=%#v,address=%p\n",*arr,&arr)
}

func main() {
   a := [3]int{89,90,91}
   modifyArray(&a)
   fmt.Printf("1. arr=%#v,addreess=%p\n",a,&a)
}
  • 切片传参: 切片是引用类型,底层是指针,所以可以直接修改
代码语言:javascript
复制
func modifySlice(a []int) {
   fmt.Printf("2.slice=%v,address=%p\n",a,&a)
   a[0] = 90
   fmt.Printf("3.slice=%v,address=%p\n",a,&a)
}

func main() {
   a := []int{89,90,91}
   modifySlice(a)
   fmt.Printf("1. silce=%#v,address=%p\n",a,&a)
}

指针类型

  • make用来分配引用类型的内存,例如:map,channel,slice
  • new用来分配除引用类型的所有其他类型的内存,例如: int,数组等
代码语言:javascript
复制
func newPoints() {
   var p *int = new(int)
   fmt.Printf("p=%v,address=%p\n",p,&p)
   *p = 100
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

type User struct {
   Name     string
   Age      int
}

func StructPoint() {
   var pUser *User = new(User)
   pUser.Name = "alex"
   pUser.Age = 19
   fmt.Printf("user:%v\n",*pUser)
}

func newSlice() {
   var p *[]int = new([]int)
   *p = make([]int,10)
   (*p)[0] = 100
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

func newMap() {
   var p *map[string]int = new(map[string]int)
   *p = make(map[string]int)
   (*p)["key1"] = 100
   (*p)["key2"] = 200
   fmt.Printf("p=%v,address=%p\n",*p,&p)
}

func main() {
   newPoints()
   StructPoint()
   newSlice()
   newMap()
}

值拷贝和引用拷贝

  • 值拷贝就是将拷贝对象重新开辟内存空间,然后将拷贝值放入新的内存空间
  • 引用拷贝就是拷贝内存地址,指向同一个值
代码语言:javascript
复制
func valueCopy() {
   a := 10
   b := a
   fmt.Printf("a=%d,address a=%p,b=%d,address b=%p\n",a,&a,b,&b)
   c := 10
   d := &c
   fmt.Printf("c=%d,address c=%p,d=%d,address d=%p\n",c,&c,*d,d)
}

面向对象编程

方法的定义

  • 跟其他语言不一样,go的方法采用另外一种方式实现
  • Go的方法是在函数前面加上一个接受者,这样编译器就知道这个方法属于哪个类型了
代码语言:javascript
复制
type Students struct {
   Name string
   Age  int
}

//定义了值类型为Students的方法
func (s Students) GetName() string{
   return s.Name
}

//修改需要指针类型的方法
func (s *Students) SetName(name string) {
   s.Name = name
}

func main() {
   var s1 Students  = Students{
      Name:"s1",
      Age:12,
   }
   name := s1.GetName()
   fmt.Printf("name=%s\n",name)

   //修改name
   s1.SetName("s2")
   name = s1.GetName()
   fmt.Printf("name=%s\n",name)
}
  • 可以为当前包内的任何类型增加方法
代码语言:javascript
复制
//定义一个integer类型
type Integer int64

func (i Integer) Print()  {
   fmt.Printf("i=%d\n",i)
}

func (i *Integer) Set(b int64) {
   *i = Integer(b)
}

func main() {
   var a Integer
   a = 1000
   fmt.Printf("a=%d\n",a)
   var b int64 = 500
   a = Integer(b)
   fmt.Printf("a=%d\n",a)
   a.Print()
   a.Set(10000)
   a.Print()
}
  • 函数不属于任何类型,方法属于特定类型
  • 指针类型作为接受者
  • 值类型和指针类型作为接受者的区别
    • 指针类型的话可以修改
    • 值类型只能作为只读的
    • 一般将指针类型作为读写的接受者即可
代码语言:javascript
复制
//定义一个integer类型
type Integer int64

func (i *Integer) Print()  {
   fmt.Printf("i=%d\n",*i)
}

func (i *Integer) Set(b int64) {
   *i = Integer(b)
}

func main() {
   var a Integer
   a = 1000
   fmt.Printf("a=%d\n",a)
   var b int64 = 500
   a = Integer(b)
   fmt.Printf("a=%d\n",a)
   a.Print()
   a.Set(10000)
   a.Print()
}

什么时候使用指针类型

  • 需要修改接受者中的值的时候
  • 接受者是大对象的时候,拷贝副本代价比较大
  • 一般来时,通常使用指针类型做为接受者
代码语言:javascript
复制
type Users struct {
   s1 [100000000]int64
   s2 [100000000]int64
   s3 [100000000]int64
   s4 [100000000]int64
}

func (u *Users) SetValue() {
   for i :=0;i<len(u.s1);i++ {
      u.s1[i] = 1
      u.s2[i] = 1
      u.s3[i] = 1
      u.s4[i] = 1
   }
}

func main() {
   var u *Users = new(Users)
   start := time.Now().UnixNano()
   u.SetValue()
   end := time.Now().UnixNano()
   fmt.Printf("总耗时:%v ms\n",(end-start)/1000000)
}

方法的继承

  • 结构体继承
  • 方法继承
代码语言:javascript
复制
type Animal struct {
   Name string
   Age  int
}

func (a *Animal) SetName(name string) {
   a.Name = name
}

func (a *Animal) SetAge(age int) {
   a.Age = age
}

func (a *Animal) Print() {
   fmt.Printf("a.name=%s a.age=%d\n",a.Name,a.Age)
}

type Brids struct {
   //继承父类,使用指针,初始化的时候也需要初始化父类
   *Animal
}

func (b *Brids) Fly() {
   fmt.Printf("name %s is flying \n",b.Name)
}

func main() {
   //继承父类,使用指针,初始化的时候也需要初始化父类
   var b *Brids = &Brids{
      &Animal{},
   }
   //继承了父类的方法
   b.SetName("birds")
   b.SetAge(12)
   //调用自己的方法
   b.Fly()
}
多重继承与冲突解决
  • 不推荐多重继承

结构体转成json(序列化)

代码语言:javascript
复制
type Animal struct {
   Name string
   Age  int
}

func (a *Animal) SetName(name string) {
   a.Name = name
}

func (a *Animal) SetAge(age int) {
   a.Age = age
}

func (a *Animal) Print() {
   fmt.Printf("a.name=%s a.age=%d\n",a.Name,a.Age)
}

type Brids struct {
   //继承父类,使用指针,初始化的时候也需要初始化父类
   *Animal
}

func (b *Brids) Fly() {
   fmt.Printf("name %s is flying \n",b.Name)
}

func main() {
   //继承父类,使用指针,初始化的时候也需要初始化父类
   var b *Brids = &Brids{
      &Animal{},
   }
   //继承了父类的方法
   b.SetName("birds")
   b.SetAge(12)
   //调用自己的方法
   b.Fly()
   // json序列化
   data,err := json.Marshal(b)
   fmt.Printf("marshal result:%s,error :%v\n",data,err)
   //反序列化:变成结构体
   var c Brids
   json.Unmarshal(data,&c)
   fmt.Printf("%#v\n",c.Animal)
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结构体后续&指针
    • 指针
      • 变量和内存地址
      • 指针的定义与取值
      • 指针变量传参
      • 指针类型
      • 值拷贝和引用拷贝
    • 面向对象编程
      • 方法的定义
      • 什么时候使用指针类型
      • 方法的继承
      • 结构体转成json(序列化)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档