首页  >  文章  >  后端开发  >  ## 为什么我可以在 Go 中调用值的指针方法?

## 为什么我可以在 Go 中调用值的指针方法?

Barbara Streisand
Barbara Streisand原创
2024-10-25 13:21:02297浏览

## Why Can I Call a Pointer Method on a Value in Go?

Go 接收器方法调用语法混乱

在《Effective Go》的“指针与值”部分中,它指出“可以在指针和值上调用值方法” ,但指针方法只能在指针上调用。”这是因为指针方法可以修改接收器,并且在值的副本上调用它们将导致这些修改被丢弃。

但是,一些开发人员遇到了一种情况,他们能够对值调用指针方法,这似乎与记录的语法规则相矛盾。为了澄清这种困惑,我们将更详细地探讨这种行为。

考虑以下 Go 代码:

<code class="go">package main

import (
  "fmt"
  "reflect"
)

type age int

func (a age) String() string {
  return fmt.Sprintf("%d yeasr(s) old", int(a))
}

func (a *age) Set(newAge int) {
  if newAge >= 0 {
    *a = age(newAge)
  }
}

func main() {
  var vAge age = 5
  pAge := new(age)

  fmt.Printf("TypeOf =>\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge),
    reflect.TypeOf(pAge))

  fmt.Printf("vAge.String(): %v\n", vAge.String())
  fmt.Printf("vAge.Set(10)\n")
  vAge.Set(10)
  fmt.Printf("vAge.String(): %v\n", vAge.String())

  fmt.Printf("pAge.String(): %v\n", pAge.String())
  fmt.Printf("pAge.Set(10)\n")
  pAge.Set(10)
  fmt.Printf("pAge.String(): %v\n", pAge.String())
}</code>

在此示例中,我们使用两个方法定义年龄类型: String( )(值方法)和 Set()(指针方法)。该代码创建了两个变量:vAge(年龄类型的值)和 pAge(指向年龄值的指针)。

尽管文档表明 vAge.Set() 不应该是有效语法,但代码编译时没有错误。这是因为 vAge 是可寻址的,这意味着它有一个可以引用的内存地址。根据语言规范,如果 x 的方法集包含 m,则对可寻址变量 x 的方法调用 x.m() 有效。

在这种情况下,vAge 是可寻址的,并且由于 *age 的方法集包含 Set () 中,调用 vAge.Set() 是 (&vAge).Set() 的简写符号。本质上,&隐式使用运算符来获取指向 vAge 的指针。

因此,代码表明确实可以在指针上调用值方法,因为在可寻址值上调用它们相当于在指向该值的指针上调用方法价值。指针方法 Set() 仍然只能在指针上调用,但在值可寻址的情况下,隐式取消引用允许语法 vAge.Set() 有效。

以上是## 为什么我可以在 Go 中调用值的指针方法?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn