2012-01-07 266 views
6

在Go編程語言中;指針指針如何變得有用?什麼是指向指針的指針?

(爲什麼他們不違法,如果他們是不是真的有用嗎?)

+6

指向任何數據的指針都很有用。指針是數據。所以指向指針的指針是有用的,指針指向的指針也是如此...... – 2012-01-07 08:27:50

+0

我同意,但由於沒有指針算術,也沒有任何指針比指向Go的指針,它們確實有點沒用。 – thwd 2012-01-07 10:07:42

+0

Go中有指針運算。你可以使用'unsafe'包來獲得一個你可以自由使用的'uintptr'。在某些情況下,這種方法可能會導致更高效的代碼,但總的來說,應該避免。 – tux21b 2012-01-07 10:43:03

回答

16

任何數據類型的有效性取決於正在解決該問題,並用於解決問題的方法。如果一個數據類型不適合這個問題,那麼它就不適合這個問題 - 而且沒有什麼更多的了。

Go編程語言(以及大多數其他編程語言)基於簡單程序員可以用來構建新數據類型的規則。一些這些規則是:

  • *T:創建是一個指針到T
  • [10]T一個新的數據類型:TS
  • 的陣列
  • struct { t T; u U ... }:含有T作爲一個部件的結構
  • ...

程序員可以通過編寫這些簡單的規則來創建複雜的數據類型。可能的數據類型總數超過了有用數據類型的數量。顯然,存在(並且必須存在)根本沒有用的數據類型。這只是建立新數據類型的規則很簡單的事實的自然結果。

**T類型屬於不太可能出現在程序中的類型的類別。有可能編寫*****T的事實並不意味着這種類型必須非常有用。


最後,回答你的問題

類型**T通常出現在我們要T類型的值的用戶重定向到T類型的另一個值上下文,但對於某些原因我們無法訪問所有用戶的價值或發現用戶會花費太多時間:

  1. 我們不想複製的值(出於某種原因)
  2. 我們希望T類型的值的所有用戶通過指針訪問值
  3. 我們要快速重定向所有用戶T類型的特定值的另一個值

在這種情況下,使用**T是自然的,因爲它使我們能夠實現在O第三步驟(1):

type User_of_T struct { 
    Value **T 
} 

// Redirect all users of a particular value of type T 
// to another value of type T. 
func (u *User_of_T) Redirect(t *T) { 
    *(u.Value) = t 
} 
+0

雖然這是一個聰明的解決方案。 – Tarik 2017-10-16 17:44:48

3

在C指針指針中很常見。例如:

  • 更多維陣列(例如字符串數組,char** argv可能是這裏最突出的例子)
  • 指針作爲輸出參數

在圍棋然而,指向指針的指針是相當稀有。不是通過指針訪問數組,而是有一個切片類型(它也在內部存儲指針)。所以,你仍然可以在Go中使用一片切片來獲得相同的間接性,但在這裏通常不會看到像**int這樣的內容。

然而第二個例子可能仍然適用於Go程序。假設你有一個函數,它應該能夠改變一個作爲參數傳遞的指針。在這種情況下,您必須將指針傳遞給該指針,以便您可以更改原始指針。這在C中非常常見,因爲函數只能返回一個值(通常是某種錯誤代碼),並且如果要返回一個額外的指針,則必須將該指針的指針用作輸出參數。 Go中的一個函數可以返回多個值,所以指向指針的指針的出現也很少見。但是在某些情況下,它們可能仍然有用並可能導致更好的API。

例如,atomic.StorePointer函數可能是指針指向標準庫中指針的罕見但隱藏的用例之一。

5

當您將指針傳遞給函數時,函數會獲得副本。因此,給定的指針分配新的值不會導致其分配給原來的一個:

type Smartphone struct { 
    name string 
} 

type Geek struct { 
    smartphone *Smartphone 
} 

func replaceByNG(s **Smartphone) { 
    *s = &Smartphone{"Galaxy Nexus"} 
} 

func replaceByIPhone(s *Smartphone) { 
    s = &Smartphone{"IPhone 4S"} 
} 

func main() { 
    geek := Geek{&Smartphone{"Nexus S"}} 
    println(geek.smartphone.name) 

    replaceByIPhone(geek.smartphone) 
    println(geek.smartphone.name) 

    replaceByNG(&geek.smartphone) 
    println(geek.smartphone.name) 
} 

輸出是:

Nexus S 
Nexus S 
Galaxy Nexus 
+0

真正有用的答案,這是我發現試圖修改另一個函數切片 – 2018-02-21 00:30:10

2

Linus Torvalds的最近提到指針的指針如何領導好品味(C語言)編寫。參見(其中包括)Brian Barto's blog post