为了账号安全,请及时绑定邮箱和手机立即绑定

我不明白什么时候在go上使用指针

我不明白什么时候在go上使用指针

Go
弑天下 2022-08-24 10:41:35
我正在做一个关于围棋语言的游览,我有一个关于指针的问题。示例代码 (https://tour.golang.org/methods/19):package mainimport (    "fmt"    "time")type MyError struct {    When time.Time    What string}func (e *MyError) Error() string {    return fmt.Sprintf("at %v, %s",        e.When, e.What)}func run() error {    return &MyError{        time.Now(),        "it didn't work",    }}func main() {    if err := run(); err != nil {        fmt.Println(err)    }}在这种情况下,它使用*MyError和&MyError,但我试图删除*和&,它工作正常。为什么他们在此示例中使用指针?与正态变量有什么区别?何时应使用指针?
查看完整描述

2 回答

?
UYOU

TA贡献1878条经验 获得超4个赞

“我什么时候应该使用指针?”是一个非常大的问题,没有一个简单的答案。指针是一种传递对值(而不是值本身)的引用的方法,允许您修改原始值或“查看”对该值的修改。它还可以防止复制,在非常有限的情况下,复制可能是性能改进(不要一直传递指针,因为它可能是性能改进)。最后,指针还允许您表示“虚无”,每个指针都可以是 。这既是祝福也是诅咒,因为您必须在访问每个指针之前检查它是否是。nilnil

在您的具体示例中,返回工作的原因是因为您的函数对值(指向 )而不是对自身的值进行操作。这意味着 实现接口,因此可以分配给类型,因此可以从任何期望将 a 作为返回值的函数返回。&MyErrorError()*MyErrorMyErrorMyError*MyErrorErrorerrorerror

返回本身不起作用,因为不是.Go在处理函数接收器时做了一些有用的事情:它会允许你在a上调用任何方法,或者如果接收器是,但它允许你在a上调用方法,如果类型是 - 也就是说,Go不会凭空为你“创建”指针。MyErrorMyError*MyErrorMyError*MyError*MyError*MyError*MyError

如果您要从 中删除 ,您将告诉 Go 适用于 的任何实例,这意味着两者都将履行该协定。这就是为什么当您不使用指针接收器时,以下两者都有效的原因:*func (e* MyError)Error()MyError*MyErrorMyError

func (e MyError) Error() string {}


var _ error = MyError{} // Valid

var _ error = &MyError {}


查看完整回答
反对 回复 2022-08-24
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

在这种特殊情况下,使用指针不会有任何区别。以下是查看它的一种方式:


在 Go 中,所有变量都按值传递。这意味着:


type T struct {...}


func f(value T) {..}


f(t)

上面,作为值传递。这意味着当调用时,编译器会创建的副本并将其传递给 。对该副本所做的任何修改都不会影响用于调用 。tftfftf


如果使用指针:


func f(value *T) {...}


f(&t)

在上面,编译器将创建一个指向 的指针,并将其副本传递给 。如果对 进行更改,则这些更改将在 used to call 的实例上进行。换句话说:tffvaluetf


type T struct {

  x int

}


func f(value T) {

   value.x=1

}


func main() {

   t:=T{}

   f(t)

   fmt.Println(t.x)

}

这将打印 0,因为 所做的修改是在 的副本上完成的。ft


func f(value *T) {

   value.x=1

}


func main() {

   t:=T{}

   f(&t)

   fmt.Println(t.x)

}

上面,它会打印1,因为调用会改变。ft


同样的想法也适用于方法和接收器:


type T struct {

   x int

}


func (t T) f() {

   t.x=1

}


func main() {

   t:=T{}

   t.f()

   fmt.Println(t.x)

}

上述程序将打印 0,因为该方法修改了 的副本。t


func (t *T) f() {

   t.x=1

}


func main() {

   t:=T{}

   t.f()

   fmt.Println(t.x)

}

上面的程序将打印 1,因为该方法的接收器是用指针声明的,而调用等效于 。t.f()f(&t)


因此,在传递参数时使用指针,或者在声明方法时,如果要修改对象,或者如果复制对象的成本太高,请使用指针。


这只是关于指针参数的故事的一小部分。


查看完整回答
反对 回复 2022-08-24
  • 2 回答
  • 0 关注
  • 74 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信