请在GoLang中解释&和*指针

时间:2015-10-01 00:08:52

标签: pointers go

我最近开始学习GoLang。当我尝试在Go函数中传递变量作为参数时,编译器会抛出错误的多个实例。我有时通过在变量前面使用指针来调试它。 &和*指针似乎都清除了错误。虽然,我想了解原因。我想知道&和*之间的区别是什么,以及何时应该使用它们。谢谢!

func (ctx *NewContext) SendNotification(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {

    decoder := json.NewDecoder(req.Body)

    var u User

    if err := decoder.Decode(&u); err != nil {
        http.Error(rw, "could not decode request", http.StatusBadRequest)
        return
    }
}

6 个答案:

答案 0 :(得分:39)

在上面的示例中,您将u定义为User类型,但不是指向User的指针。所以你需要& u因为json包中的Decode函数需要一个地址或指针。

如果您像这样创建了User实例:u:= new(User)它将是一个指针,因为新函数返回一个指针。您还可以创建一个指向用户的指针,如下所示:var u * User。如果你做了其中任何一个,你将不得不取出&在调用Decode以使其工作。

指针基本上是包含地址的变量。当你把&在变量前面它返回地址。 *可以读作'重定向'。所以当你创建这样的指针时:

var x * int

这可以读取,因为x将重定向到int。当你为x赋值时,你会给它一个这样的地址: y:= 10 x =& y

其中y是某个int。因此,如果您要打印x,您将获得y的地址,但是如果您打印出* x,您将重定向到x的点,即y的值为10.如果您要打印出来& x ,你会得到指针x的地址。

如果你试图打印* y,它只是一个int而不是一个指针,它会抛出一个错误,因为你将重定向一些不是重定向到的地址的值。

运行下面的指针乐趣:

package main

import "fmt"

func main() {
    var y int
    var pointerToY *int
    var pointerToPointerToInt **int

    y = 10
    pointerToY = &y
    pointerToPointerToInt = &pointerToY

    fmt.Println("y: ", y)
    fmt.Println("pointerToY: ", pointerToY)
    fmt.Println("pointerToPointerToInt: ", pointerToPointerToInt)

    fmt.Println("&y: ", &y)     // address of y
    fmt.Println("&pointerToY: ", &pointerToY)// address of pointerToY
    fmt.Println("&pointerToPointerToInt: ", &pointerToPointerToInt) // address of pointerToPointerToInt

    // fmt.Println(*y) throws an error because 
    // you can't redirect without an address.. 
    // y only has int value of 10
    fmt.Println("*pointerToY: ", *pointerToY) // gives the value of y
    fmt.Println("*pointerToPointerToInt: ", *pointerToPointerToInt)     // gives the value of pointerToY which is the address of y

    fmt.Println("**pointerToPointerToInt: ", **pointerToPointerToInt)    // this gives 10, because we are redirecting twice to get y

    if pointerToY == *pointerToPointerToInt {
        fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
    }

    if pointerToY == &y {
        fmt.Println("'pointerToY == &y' are the same!")
    }

    if &pointerToY == pointerToPointerToInt {
        fmt.Println("'&pointerToY == pointerToPointerToInt' are the same!")
    }

    if y == **pointerToPointerToInt {
        fmt.Println("'y == **pointerToPointerToInt' are the same!")
    }

    if pointerToY == *pointerToPointerToInt {
        fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
    }

}

希望这有帮助!

答案 1 :(得分:8)

我会引用一个聪明的家伙:

  

&安培;变量名前面用于检索where的地址   存储此变量的值。那个地址就是指针   去商店。

     在类型名称前面的

*表示声明的变量将存储该类型的另一个变量的地址(不是该值的值)   类型)。

     在指针类型变量前面的

*用于检索存储在给定地址的值。在Go中,这称为解除引用。

来源:http://piotrzurek.net/2013/09/20/pointers-in-go.html

答案 2 :(得分:2)

显示代码执行顺序的简单示例。

   import (
        "fmt"
    )

    func main() {
        x := 0
        fmt.Println("Step 1", x)
        foo(&x)
        fmt.Println("Step 4", x)
    }

    func foo(y *int) {

        fmt.Println("Step 2", *y)
        *y = 100
        fmt.Println("Step 3", *y)
    }
/*
 Steps  Result
   1      0
   2      0
   3      100
   4      100
 */

答案 3 :(得分:1)

pointer用于指向指向address,还可以获取存储地址在存储地址中的值

添加一个示例以帮助理解pointeraddress

Demo code

package main

import "fmt"

func main() {
    var y int
    var pointerToY *int
    var x int
    //var willThrowErrorVariable int

    y = 10
    pointerToY = &y
    //willThrowErrorVariable = &y 
    x = *pointerToY

    fmt.Println("y: ",y)
    fmt.Println("y's address using pointerToY: ",pointerToY)

    y = 4
    fmt.Println("====================================================")
    fmt.Println("Address of y after its value is changed: ",pointerToY)
    fmt.Println("value of y using pointer after its value is changed: ",*pointerToY)
    fmt.Println("Value of x after y value is changed: ",x)
}
  

输出

y:  10
y's address using pointerToY:  0x414020
====================================================
Address of y after its value is changed:  0x414020
value of y using pointer after its value is changed:  4
Value of x after y value is changed:  10

我们可以看到,值可能会更改,但是address&)保持不变,因此pointer*)指向{{ 1}}。

在上面的示例中,

  1. address保留了指向pointerToY的{​​{1}}的指针。
  2. address保留我们使用y中的xpointer传递给它的值。
  3. 更改address的值后,y仍然具有y,但是如果我们尝试使用x10来访问值( pointerToY ),我们得到pointer

答案 4 :(得分:1)

对于这个答案,我将尝试用一个变量值来解释。指针也可以指向结构值。

&返回一个指向变量值的指针。

*读取指针指向的变量值。

示例:

func zero(xPointer *int) {
  *xPointer = 0
  fmt.Println(*xPointer)
}

func main() {
  x := 1
  zero(&x)
  fmt.Println(x) // x is 0
}

答案 5 :(得分:0)

我想通过一个例子来解释指针(*&)的概念:

考虑一个例子,我们希望在函数的帮助下增加一个变量1

package main

import (
    "fmt"
)

func main() {
    x := 7
    fmt.Print(inc(x))
}
func inc(x int) int {
    return x + 1
}

以上解释:我们有一个函数func inc(x int) int,它接受​​一个整数并通过执行递增返回一个整数。

<块引用>

注意:请注意 func inc(x int) int 返回一个 int,现在如果我们没有返回类型会发生什么 功能??这是通过指针解决的。

看下面的代码:

package main

import (
    "fmt"
)

func main() {
    x := 7
    inc(&x)
    fmt.Print(x)

}
func inc(x *int) {
    *x++
}

以上代码说明:

现在我们的函数 func inc(x *int) 没有返回类型,我们不能从这个函数中得到任何递增的值,但是我们可以做的是我们可以向这个函数发送一个位置(地址)并告诉它递增将此位置的值加一,现在我们可以从 main() 内部访问该位置,我们的工作就完成了。

快速提示:变量前面的 * 表示该变量中存储了什么??变量前面的 & 表示该变量的内部地址是什么?