2013-03-20 35 views
4

如何獲取接口內的值的地址?獲取接口內的值地址

我存儲在一個接口的結構,在list.List元素:

import "container/list" 
type retry struct{} 
p := &el.Value.(retry) 

但我得到這個:

cannot take the address of el.Value.(retry) 

這是怎麼回事?由於結構存儲在接口中,爲什麼我不能得到指向它的指針?

回答

5

要理解爲什麼這是不可能的,它有助於思考什麼接口可變實際盟友是。一個接口值佔用兩個單詞,第一個描述所包含值的類型,第二個(a)保存所包含的值(如果它適合在單詞中)或(b)指向存儲的指針(如果該值不符合一個詞)。

要注意的重要事項是(1)包含的值屬於接口變量,(2)當爲變量分配新值時,可以重新使用該值的存儲。知道了,考慮下面的代碼:

var v interface{} 
v = int(42) 
p := GetPointerToInterfaceValue(&v) // a pointer to an integer holding 42 
v = &SomeStruct{...} 

現在的整數存儲已經被重複使用,以容納一個指針,而現在*p是指針的整數表示。你可以看到這是如何破壞類型系統的,因此Go沒有提供這樣做的方法(使用unsafe包之外)。

如果您需要一個指向您存儲在列表中的結構體的指針,那麼一個選項將存儲指向列表中的結構體的指針,而不是直接存儲結構體的值。或者,您可以將*list.Element值作爲引用傳遞給包含的結構。

+0

這似乎更合理。我認爲這足以說明你無法對所含價值的存儲做出任何保證就足夠了。 – 2013-03-22 07:34:25

+0

第二個想法是,我沒有看到任何情況下可以調整接口存儲與接口的大小,而無需重新定位接口。 – 2013-03-24 11:13:33

+0

好吧,我給出了一個用於接口值重用的存儲的例子。由於該語言不能保證存儲不會被重用,因此不要給你一個指向該存儲的類型指針。由於接口值將更大的值存儲在單獨分配的內存中(使用第二個字作爲指向該存儲的指針),您將通過在您的列表中存儲'* retry'值來使用相同數量的內存。 – 2013-03-26 06:54:26

2

第一個近似值:你不能那樣做。即使你可以,p本身必須有interface{}類型,並不會太有用 - 你不能直接解引用它。

強制性問題是:你想解決什麼問題?

最後但並非最不重要的:接口定義行爲不結構。通常直接使用接口的底層實現類型會破壞接口契約,儘管可能存在非一般的合法情況。但是這些已經爲type switch statement提供了一個靜態已知類型的有限集合。

+0

我不明白爲什麼這是必要的。在類型聲明之後,我應該能夠獲取由相應接口返回的右值引用所指向的值的地址。 – 2013-03-20 14:09:46

+1

@MattJoiner:如果接口中包含的值不是指針類型,則類型斷言提供一個副本。但是你的問題題爲:_「在地址__inside__一個界面_」。 (強調我的)。 IOW,如果你想要一個指向原來的非指針類型的指針,那麼輸入assertion將不會起作用,因爲接口在內部只攜帶一個指向這個實例的指針(模數值適合機器字)。你爲什麼不直接在界面中放置一個指向值的指針?然後你用語言支持的方式直接獲得你的想法。 – zzzz 2013-03-20 14:50:42

2

類型斷言是導致兩個值的表達式。在這種情況下的地址是不明確的。

p, ok := el.Value.(retry) 
if ok { 
    // type assertion successful 
    // now we can take the address 
    q := &p 
} 

從評論:

注意,這是一個指向指針的值的副本,而不是本身的價值。

James Henstridge

的解決問題的辦法是簡單因此;在界面中存儲一個指針,而不是一個值。

+2

請注意,這是一個指向該值的副本的指針,而不是指向該值本身的指針。 – 2013-03-20 11:58:50

+0

這是不合理的。當然,我將它賦值爲自動變量'p'後有一個副本。但雖然它仍然是一個右值,我應該能夠獲取該值存儲在界面中的值的地址。由於接口以內嵌方式存儲在'Value'中,因此假設接口_中的值是堆分配的,因此可以在適當的位置進行修改。 – 2013-03-20 14:12:50

+2

@MattJoiner:接口包含的大值實際上是堆分配的。但是指向該值的指針是一個非指定的,未公開的實現細節(關於語言本身以及我不能推薦使用的模數技術)。如果你需要一個接口的指針,那麼在接口中放一個指針_into_。 – zzzz 2013-03-20 14:57:12

2

Get pointer to interface value?

有沒有一種方法,給定的接口類型的變量,得到一個 指向存儲在變量中的值嗎?

這是不可能的。

羅布派克

接口值不一定尋址的。例如,

package main 

import "fmt" 

func main() { 
    var i interface{} 
    i = 42 
    // cannot take the address of i.(int) 
    j := &i.(int) 
    fmt.Println(i, j) 
} 

Address operators

對於類型T的操作數X,寫入動作& X生成 指針類型* T的至x。操作數必須是可尋址的,即 變量,指針間接或片索引操作; 或可尋址結構操作數的字段選擇器;或者可尋址陣列的索引操作的數組 。作爲 可尋址性要求的例外,x也可以是複合文字。

參考文獻:

Interface types

Type assertions

Go Data Structures: Interfaces

Go Interfaces