• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Go进阶方法的值类型和指针类型区别

武飞扬头像
嵌入式职场
帮助1

目录

值类型和指针类型


值类型和指针类型

方法也有值类型的方法和指针类型的区别,也就是以下两种receiver:

  1.  
    func (p person) setname(name string) { p.name = name }
  2.  
    func (p *person) setage(age int) { p.age = age }

setname()方法中是值类型的receiver,setage()方法中是指针类型的receiver。它们是有区别的。

  • 首先,setage()方法的p是一个指针类型的person实例,所以方法体中的p.age实际上等价于(*p).age。再者,方法就是函数,Go中所有需要传值的时候,都是按值传递的,也就是拷贝一个副本

setname()中,除了参数name string需要拷贝,receiver部分(p person)也会拷贝,而且它明确了要拷贝的对象是值类型的实例,也就是拷贝完整的person数据结构。但实例有两种类型:值类型和指针类型。

  • (p person)无视它们的类型,因为receiver严格规定p是一个值类型的实例。所以无论是指针类型的p1实例还是值类型的p2实例,都会拷贝整个实例对象。对于指针类型的实例p1,前面说了,在需要的时候,Go会自动解除引用,所以p1.setname()等价于(*p1).setname()

只要receiver是值类型的,无论是使用值类型的实例还是指针类型的实例,都是拷贝整个底层数据结构的,方法内部访问的和修改的都是实例的副本。所以,如果有修改操作,不会影响外部原始实例。

  • setage()中,receiver部分(p *person)明确指定了要拷贝的对象是指针类型的实例,无论是指针类型的实例p1还是值类型的p2,都是拷贝指针。所以p2.setage()等价于(&p2).setage()

也就是说,只要receiver是指针类型的,无论是使用值类型的实例还是指针类型的实例,都是拷贝指针,方法内部访问的和修改的都是原始的实例数据结构。所以,如果有修改操作,会影响外部原始实例。

那么选择值类型的receiver还是指针类型的receiver?一般来说选择指针类型的receiver。

  1.  
    package main
  2.  
     
  3.  
    import "fmt"
  4.  
     
  5.  
    type person struct {
  6.  
    name string
  7.  
    age int
  8.  
    }
  9.  
     
  10.  
    func (p person) setname(name string) {
  11.  
    p.name = name
  12.  
    }
  13.  
    func (p *person) setage(age int) {
  14.  
    p.age = age
  15.  
    }
  16.  
     
  17.  
    func (p *person) getname() string {
  18.  
    return p.name
  19.  
    }
  20.  
    func (p *person) getage() int {
  21.  
    return p.age
  22.  
    }
  23.  
     
  24.  
    func main() {
  25.  
    // 指针类型的实例
  26.  
    p1 := new(person)
  27.  
    p1.setname("longshuai1")
  28.  
    p1.setage(21)
  29.  
    fmt.Println(p1.getname()) // 输出""
  30.  
    fmt.Println(p1.getage()) // 输出21
  31.  
     
  32.  
    // 值类型的实例
  33.  
    p2 := person{}
  34.  
    p2.setname("longshuai2")
  35.  
    p2.setage(23)
  36.  
    fmt.Println(p2.getname()) // 输出""
  37.  
    fmt.Println(p2.getage()) // 输出23
  38.  
    }
学新通

上面分别创建了指针类型的实例p1和值类型的实例p2,但无论是p1还是p2,它们调用setname()方法设置的name值都没有影响原始实例中的name值,所以getname()都输出空字符串,而它们调用setage()方法设置的age值都影响了原始实例中的age值。

方法不过是一种特殊的函数,只需将其还原,就知道 receiver T 和 *T 的差别。

  1.  
    package main
  2.  
     
  3.  
    import "fmt"
  4.  
     
  5.  
    type Data struct {
  6.  
    x int
  7.  
    }
  8.  
     
  9.  
    func (self Data) ValueTest() { // func ValueTest(self Data);
  10.  
    fmt.Printf("Value: %p\n", &self)
  11.  
    }
  12.  
     
  13.  
    func (self *Data) PointerTest() { // func PointerTest(self *Data);
  14.  
    fmt.Printf("Pointer: %p\n", self)
  15.  
    }
  16.  
     
  17.  
    func main() {
  18.  
    d := Data{}
  19.  
    p := &d
  20.  
    fmt.Printf("Data: %p\n", p)
  21.  
     
  22.  
    d.ValueTest() // ValueTest(d)
  23.  
    d.PointerTest() // PointerTest(&d)
  24.  
     
  25.  
    p.ValueTest() // ValueTest(*p)
  26.  
    p.PointerTest() // PointerTest(p)
  27.  
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfiaie
系列文章
更多 icon
同类精品
更多 icon
继续加载