我最近开始学习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
}
}
答案 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中,这称为解除引用。
答案 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
,还可以获取存储地址在存储地址中的值
添加一个示例以帮助理解pointer
与address
:
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}}。
在上面的示例中,
address
保留了指向pointerToY
的{{1}}的指针。address
保留我们使用y
中的x
到pointer
传递给它的值。address
的值后,y
仍然具有y
,但是如果我们尝试使用x
到10
来访问值( 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()
内部访问该位置,我们的工作就完成了。
快速提示:变量前面的 *
表示该变量中存储了什么??变量前面的 &
表示该变量的内部地址是什么?