首页 > 解决方案 > go 什么时候使用 & 或不使用?

问题描述

我很困惑在声明变量时是否使用&with go 并使用结构初始化

假设我们有一个结构包装器

type HttpResult struct {
    Status int32       `json:"status"`
    Msg    string      `json:"msg"`
    Data   interface{} `json:"data,omitempty"` 
}

和一个定义用户模型的结构


type OmUser struct {
    Id       primitive.ObjectID `json:"id" bson:"_id,omitempty"`
    Name     string             `json:"name"`
    Password string             `json:"password"`
    Email    string             `json:"email"`
}

以下声明似乎给出了相同的结果:

myOmUser := OmUser{ //note no & sign here
   Name: "Tony",
   Password: "mypass",
   Email: "tony@foo.com"
}

httpResult := &HttpResult{
        Status: 0,
        Msg:    "ok",
        Data:   myOmUser,
}

js, _ := json.Marshal(httpResult)

fmt.Println(js)

或者

myOmUser := &OmUser{ //note the & sign
   Name: "Tony",
   Password: "mypass",
   Email: "tony@foo.com"
}

httpResult := &HttpResult{
        Status: 0,
        Msg:    "ok",
        Data:   myOmUser,
}

js, _ := json.Marshal(httpResult)

fmt.Println(js)

那么,何时使用&,为什么?

标签: gopointers

解决方案


在您的特定示例中,它没有任何区别。
但是当我们看一个使用json.Unmarshal()它的例子时,会更有意义:

jsonBlob := []byte(`{"id": "1", "name": "bob", "password": "pass", "email", "hi@me.com"}`)
var newOmUser OmUser
err := json.Unmarshal(jsonBlob, &newOmUser)
if err != nil {
    panic(err)
}

这里我们事先声明了变量,然后我们使用 将&指向该变量的指针传递给Unmarshal函数。
这意味着该Unmarshal函数可以访问并更新该变量,即使它是在函数外部声明的。
如果没有&,该Unmarshal函数将获得newOmUser变量的副本,并且它将保留newOmUser我们声明为空的原始变量。

当谈到指针时,我的一般经验法则是:

除非必须,否则不要使用它们。

如果您需要使用任何解组功能,您将需要它们。还有许多其他功能可以使用它们。

这是一个快速练习,可以帮助我更多地了解指针:

func uppercase(s string) {
    s = strings.ToUpper(s)
    fmt.Println(s)
}

// Same as the uppercase() function, but works with a pointer.
func uppercasePointer(s *string) {
    *s = strings.ToUpper(*s)
    fmt.Println(*s)
}

name := "bob"
uppercase(name)   // prints 'BOB'
fmt.Println(name) // prints 'bob' - our variable was not changed

name2 := "bobpointer"
uppercasePointer(&name2) // prints 'BOBPOINTER'
fmt.Println(name2)       // prints 'BOBPOINTER' - our variable was changed

当我们调用uppercase(name)函数时,go 会复制name变量并将其发送给uppercase函数。
无论函数对它收到的副本做什么,都会保留在函数中。我们在函数外部声明的原始变量没有改变。

当我们调用uppercasePointer(&name2)函数时,我们正在发送一个指向name2我们声明的变量的指针。
该函数可以使用该指针来访问并更新name2我们之前声明的变量。

一开始你可能看不到指针的意义,但是随着你继续使用 go,你会发现它们帮助我们解决了一些复杂的问题。


推荐阅读