# 03.6 Go 指针

Go支持指针！**指针**是内存地址，它能够提升代码运行效率但是增加了代码的复杂度，C程序员深受指针的折磨。在`第2章`中当我们讨论不安全的代码时，就使用过指针，这一节哦我们将深入介绍Go指针的一些难点。另外，当你足够了解原生Go指针时，其安全性大可放心。

使用指针时，`*`可以获取指针的值，此操作成为**指针的解引用**，`*`也叫取值操作符；`&`可以获取非指针变量的地址，叫做取地址操作符。

> 通常来说，经验较少的开发者应该尽量少使用指针，因为指针很容易产生难以察觉的bug。

你可以创建一个参数为指针的函数：

> func getPointer(n \*int) {
>
> }

同样，一个函数的返回值也可以为指针：

> func returnPointer(n int) \*int {
>
> }

`pointers.go`展示了如何安全地使用Go指针，该文件分为4部分，其中第一部分是：

> ```go
> package main
>
> import "fmt"
>
> func getPointer(n *int) {
>    *n = *n * *n
> }
>
> func returnPointer(n int) *int  {
>    v := n * n
>    return &v
> }
> ```

`getPointer()`的作用是修改传递来的参数，而无需返回值。这是因为传递的参数是指针，其指向了变量的地址，所以能够将变量值的改变反映到原值上。

`returnPointer()`的参数是一个整数，返回值是指向整数的指针，尽管这样看起来并没有什么用处，但是在第四章中，当我们讨论指向结构体的指针以及其他复杂数据结构时，你就会发现这种操作的优势。

`getPointer()`和`returnPointer()`函数的作用都是求一个整数的平方，区别在于`getPointer()`使用传递来的参数存储计算结果，而`returnPointer()`函数重新声明了一个变量来存储运算结果。

第二部分:

> ```go
> func main() {
>    i := -10
>    j := 25
>
>    pI := &i
>    pJ := &j
>
>    fmt.Println("pI memory:", pI)
>    fmt.Println("pJ memory:", pJ)
>    fmt.Println("pI value:", *pI)
>    fmt.Println("pJ value:", *pJ)
> ```

`i`和 `j`是整数，`pI`和`pJ`分别是指向`i`和`j`的指针，`pI`是变量的内存地址，`*pI`是变量的值。

第三部分:

> ```go
> *pI = 123456
> *pI--
> fmt.Println("i:",i)
> ```

这里我们使用指针`pI`改变了变量`i`的值。

最后一部分代码:

> ```go
>    getPointer(pJ)
>    fmt.Println("j:",j)
>    k := returnPointer(12)
>    fmt.Println(*k)
>    fmt.Println(k)
>
> }
> ```

根据前面的讨论，我们通过修改`pJ`的值就可以将改变反映到`j`上，因为`pJ`指向了`j`变量。我们将`returnPointer()`的返回值赋值给指针变量`k`。

运行`pointers.go`的输出是：

> $ go run pointers.go
>
> pI memory: 0xc420014088 pJ memory: 0xc420014090 pI value: -10 pJ memory: 25 i: 123455 j: 625 144 0xc4200140c8

你可能对`pointers.go`中的某些代码感到困惑，因为我们在第六章才开始讨论函数及函数定义，可以去了解关于函数的更多信息。
