2012-01-07 286 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