2014-09-01 21 views
6

是否有這種行爲的原因?我想知道內存級別有什麼不同。編譯器返回「不能接受複合文字的地址」,而我可以明確地要求它這樣做。爲什麼變量的內聯實例化需要顯式地將其地址調用指針方法,而對於現有的變量,其隱含條件是

繼承人的去操場go playground link

u := User{"john"} 
fmt.Println(u.Name()) //implicit 

//fmt.Println(User{"john"}.Name()) //Error: cannot call pointer method on composite literal, cannot take the address of composite literal 
fmt.Println((&User{"jim"}).Name()) //explicit 

type User struct { 
    name string 
} 

func (u *User) Name() string { 
    return u.name 
} 

回答

6

因爲composite litteralnot addressable,直到它被分配給一個變量:

操作數必須是可尋址的,也就是說,是一個變量,指針間接或分片索引操作;或可尋址結構操作數的字段選擇器;或可尋址陣列的數組索引操作。
作爲尋址能力要求的一個例外,x也可能是一個(可能是加括號的)複合文字。

你可以把地址User{"jim"}(&User{"jim"})(字面指針)。
但是,您不能直接使用User{"jim"}(字面值,直到它被分配給變量)的值。
查看更多的this thread


This thread添加到「表達式不能尋址」的問題:

考慮的東西的地址,即到這個假想的一點是不可尋址(表達式不發生根植於一個標識符),在語義上沒有不同,然後設置目標指針的解引用值。
換句話說,下面的是等效的:

var x *int 
*x = (2 * 3) + 4 

var x *int 
x = &((2 * 3) + 4) 

由於一個表達只要它的使用扔掉,其值的地址(其經常被完全寄存器駐留,因此實際上沒有地址)在任何情況下都是毫無意義的,並且從地址獲取的唯一好處是變量聲明中的類型推斷的語法便利性(最多保存一行):

x := &((2 * 3) + 4) 

與製作任意表達式尋址一個問題:

m := map[int]int{1:2} 
x := &m[1] 
x = 3 
fmt.Println("x is", x, "while m[1] is", m[1]) 
// will print `x is 3 while m[1] is 2` 

簡而言之:這將是不清楚(和幾乎不可能進行調試)無論你是服用你希望尋址的東西的地址,或者當你採取隱式中間變量的地址(這通常是你不想要的東西)。

+0

「因爲直到它被分配給一個變量之前,複合litteral不可尋址」我想知道爲什麼。該線程不會給出令人滿意的推理/參數。 – Gnani 2014-09-01 09:34:49

+1

@Gnani,因爲文字值本身不是直接可尋址的。 &CompiteLiteral是。 – VonC 2014-09-01 09:35:56

2

是否有這種行爲的原因?

的原因行爲是,有一個例外尋址該特定符號和該異常被轉到維護的一個解釋here的原因:

他們是特殊的,因爲我們決定符號是有益 夠構造,值得一特殊情況:

Taking the address of a composite literal (§Address operators) 
generates a unique pointer to an instance of the literal's value. 

http://golang.org/doc/go_spec.html#Composite_literals 

拉斯


「隔空複合字面的(§Address運營商) 生成一個唯一指針字面的值的一個實例的地址。」 你能詳細說明一下嗎?

我認爲這意味着符號&Object{}符號是一個簡單的字面指針每次執行它創造的價值和新的指針的新實例時會創建一個指向新的價值。可尋址性異常只是由於這個文字的符號而產生的,它不像其他的可尋址符,因爲它不受&運算符的影響。

我想要一個類似於jesse's的回答 您提到的「here」鏈接。那是C.對於golang,誰能確認 ?

我的猜測是這樣的,這個符號是逃逸分析,這決定了在編譯時引用是否逃逸功能,並確定是否應在堆或堆棧(快)被分配很有幫助。從我所瞭解的變量中可以得出他們的地址被認爲是逃生分析的候選人。由於Go的主要目標之一是快速編譯,我認爲參考創建和跟蹤需要清晰。

例如,對於Item{}.Method()需要建立一個指針,並因此運行逃逸分析到Item{}值將取決於接收器類型的Method()的無論是*Item或只是Item這不必要地複雜化編譯。這就是爲什麼您使用明確的標記&Item{}來構建*Item

+0

「因爲它的例外」並不令人滿意。 「以複合文字的地址(§Addressoperators) 生成一個唯一指向文字值的實例的指針。」你能詳細說明一下嗎? 我想在你提到的「here」鏈接上與jesse's類似的答案。那是C.對於golang,任何人都可以證實嗎? – Gnani 2014-09-01 09:39:09

+0

@Gnani我加了一些可能的解釋。 – 2014-09-01 10:12:17

+0

總結VonC:變量的值並不總是穩定的堆地址;它們可能在寄存器中,在堆棧上並在函數返回後被吹走,或者可能是隨着地圖增長而在內存中移動的映射值。 – twotwotwo 2014-09-01 21:26:55

相關問題