我很困惑,在宣告一個變數時,是否應該使用&與go一起,并使用一個結構來啟動
假設我們有一個結構封裝器
type HttpResult struct {
狀態 int32 `json: "status"`
Msg string `json: "msg"`
資料 interface{}。`json: "data,omitempty"` 資料 interface{}。
}
和一個定義用戶模型的結構
。
type OmUser struct {
Id primitive.ObjectID `json: "id" bson:"_id,omitempty"`
名字 string `json: "name"`
密碼 string `json: "password"`/span>
電子郵件 string `json: "email"`/span>
}
而下面的宣告似乎給出了同樣的結果:
myOmUser := OmUser{ /note no & sign here
名字。"Tony"。
密碼。"mypass"。
電子郵件。"[email protected]"0,
Msg: "ok",
資料: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
或者
myOmUser := &OmUser{ //note the & sign
名稱。"Tony"。
密碼。"mypass"。
電子郵件。"[email protected]"0,
Msg: "ok",
資料: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
那么,什么時候使用&以及為什么?
uj5u.com熱心網友回復:
在你的特定例子中,它并沒有什么區別。
但是當我們看一個使用json.Unmarshal()的例子時,就有點意義了:
jsonBlob := []byte(`{"id": "1", "name": "bob", "password": "pass", "email", "[email protected]"}`)
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)
}
//與uppercase()函式相同,但對一個指標起作用。
func uppercasePointer(s *string) {
*s = strings.ToUpper(*s)
fmt.Println(*s)
}
name := "bob"/span>
uppercase(name) //列印'BOB'。
fmt.Println(name) //列印 'bob' - 我們的變數沒有改變。
name2 := "bobpointer"/span>
uppercasePointer(&name2) // printts 'BOBPOINTER'
fmt.Println(name2) //列印'BOBPOINTER' - 我們的變數被改變了。
當我們呼叫uppercase(name)函式時,go對name變數進行了復制,并將其發送給uppercase函式。
無論函式對它收到的副本做了什么,都會留在函式中。我們在函式外宣告的原始變數并沒有被改變。
當我們呼叫uppercasePointer(&name2)函式時,我們正在發送一個指標到我們宣告的name2變數。
該函式可以使用該指標來接觸并更新我們之前宣告的name2變數。
一開始,你可能看不到指標的意義,但是當你繼續使用go時,你會發現它們幫助我們解決一些復雜的問題。
uj5u.com熱心網友回復:
Go中的空介面型別可以容納任何型別的值。在此游覽.
。所以在你的HttpResult.Data是一個空的介面型別。所以你可以給它分配任何型別。
用&定義一個變數的區別是獲得一個該型別的指標。在這里游覽。
這顯然是兩種型別,在Go中具有兩種不同的功能。但是你可以把這兩種型別都分配給空的介面型別變數,因為它接受任何型別的值。
package main
import (
"fmt"/span>
"reflect"/span>
)
type OmUser struct {
}
func main() {
myOmUser :=OmUser{}。
myOmUser2 := &OmUser{}。
fmt.Println(reflect.TypeOf(myOmUser)) //main.OmUser
fmt.Println(reflect.TypeOf(myOmUser2)) //*main.OmUser fmt.Println(reflect.TypeOf(myOmUser2))
}
關于&的更多細節,請閱讀Go doc地址運營商
對于一個 型別的運算元x,地址操作&x產生一個指向x的*T型別的指標。 運算元必須是可尋址的,也就是說,要么是一個變數,要么是一個指標,要么是一個指向x的*T型別。 變數、指標指示或片斷索引操作;或者是一個可尋址結構操作的欄位 可尋址結構運算元的欄位選擇器;或可尋址陣列的陣列索引 可尋址陣列的索引操作。作為一個例外 可尋址要求的例外情況,x也可以是一個(可能是括號內的) 復合字面。如果對x的評估會引起運行時的 恐慌,那么 &x 的評估也會導致恐慌。
uj5u.com熱心網友回復:
fooA := &Foo{}.
fooA具有*Foo型別。
fooB := Foo{}.
fooB具有型別Foo。
https://tour.golang.org/moretypes/1
在實踐中,這意味著如果你有一個接受*Foo型別的func,你可以做以下任何一個...
func someFunc(f *Foo){
/ ...
}
fooA := &Foo{}。
someFunc(fooA)
fooB := Foo{}
someFunc(&fooB)
因此,現實中,創建你需要的任何一個都是誠實的。
uj5u.com熱心網友回復:
使用一個指標,如果:
你的結構體可能是在你需要的時候才出現的。
nil來表示沒有一個值(未初始化,未設定,等等)。在函式回傳中很有用,比如:func doSomething() (*OmUser, 錯誤) {
err := //一些錯誤。
if err != nil {
return nil, err
}
return &OmUser{}, nil.
}
在這種情況下,上述指標可以有nil值而不是零結構。
- 如果結構中有或嵌入了不能被復制的欄位,如
sync.Mutex,也可以使用指標,所以當你分配一個var時,不會意外地復制mutex 。
在所有其他情況下使用一個值。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/315480.html
標籤:
