猿问

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

我正在做一个关于围棋语言的游览,我有一个关于指针的问题。


示例代码 (https://tour.golang.org/methods/19):


package main


import (

    "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,但我试图删除*和&,它工作正常。为什么他们在此示例中使用指针?与正态变量有什么区别?何时应使用指针?


弑天下
浏览 75回答 2
2回答

UYOU

“我什么时候应该使用指针?”是一个非常大的问题,没有一个简单的答案。指针是一种传递对值(而不是值本身)的引用的方法,允许您修改原始值或“查看”对该值的修改。它还可以防止复制,在非常有限的情况下,复制可能是性能改进(不要一直传递指针,因为它可能是性能改进)。最后,指针还允许您表示“虚无”,每个指针都可以是 。这既是祝福也是诅咒,因为您必须在访问每个指针之前检查它是否是。nilnil在您的具体示例中,返回工作的原因是因为您的函数对值(指向 )而不是对自身的值进行操作。这意味着 实现接口,因此可以分配给类型,因此可以从任何期望将 a 作为返回值的函数返回。&MyErrorError()*MyErrorMyErrorMyError*MyErrorErrorerrorerror返回本身不起作用,因为不是.Go在处理函数接收器时做了一些有用的事情:它会允许你在a上调用任何方法,或者如果接收器是,但它只允许你在a上调用方法,如果类型是 - 也就是说,Go不会凭空为你“创建”指针。MyErrorMyError*MyErrorMyError*MyError*MyError*MyError*MyError如果您要从 中删除 ,您将告诉 Go 适用于 的任何实例,这意味着两者都将履行该协定。这就是为什么当您不使用指针接收器时,以下两者都有效的原因:*func (e* MyError)Error()MyError*MyErrorMyErrorfunc (e MyError) Error() string {}var _ error = MyError{} // Validvar _ error = &MyError {}

红颜莎娜

在这种特殊情况下,使用指针不会有任何区别。以下是查看它的一种方式:在 Go 中,所有变量都按值传递。这意味着:type T struct {...}func f(value T) {..}f(t)上面,作为值传递。这意味着当调用时,编译器会创建的副本并将其传递给 。对该副本所做的任何修改都不会影响用于调用 。tftfftf如果使用指针:func f(value *T) {...}f(&t)在上面,编译器将创建一个指向 的指针,并将其副本传递给 。如果对 进行更改,则这些更改将在 used to call 的实例上进行。换句话说:tffvaluetftype T struct {  x int}func f(value T) {   value.x=1}func main() {   t:=T{}   f(t)   fmt.Println(t.x)}这将打印 0,因为 所做的修改是在 的副本上完成的。ftfunc 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,因为该方法修改了 的副本。tfunc (t *T) f() {   t.x=1}func main() {   t:=T{}   t.f()   fmt.Println(t.x)}上面的程序将打印 1,因为该方法的接收器是用指针声明的,而调用等效于 。t.f()f(&t)因此,在传递参数时使用指针,或者在声明方法时,如果要修改对象,或者如果复制对象的成本太高,请使用指针。这只是关于指针参数的故事的一小部分。
随时随地看视频慕课网APP

相关分类

Go
我要回答