英文:
Please explain &, and * pointers
问题
在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
}
}
英文:
There have been multiple instances where the compiler throws an error when I try to pass variables as arguments inside Go functions. I've been able to debug this sometimes by using a pointer in front of the variable. Both &, and * pointers seem to clear the error. Though, I'd like to understand why. I'm wondering what the difference between &, and * is, and when each should be used. Thank you!
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
}
}
答案1
得分: 52
在你上面的示例中,你将u定义为User类型,但不是User的指针。所以你需要使用&u,因为json包中的Decode函数期望一个地址或指针。
如果你像这样创建User的实例:u := new(User),它将是一个指针,因为new函数返回一个指针。你也可以像这样创建一个指向User的指针:var u *User。如果你这样做了,你就需要在调用Decode时去掉&
才能正常工作。
指针基本上是保存地址的变量。当你在变量前面加上&时,它返回地址。*可以读作'redirect of'。所以当你像这样创建一个指针:
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) // y的地址
fmt.Println("&pointerToY: ", &pointerToY)// pointerToY的地址
fmt.Println("&pointerToPointerToInt: ", &pointerToPointerToInt) // pointerToPointerToInt的地址
// fmt.Println(*y) 抛出错误,因为
// 你不能没有地址进行重定向..
// y只有int值10
fmt.Println("*pointerToY: ", *pointerToY) // 给出y的值
fmt.Println("*pointerToPointerToInt: ", *pointerToPointerToInt) // 给出pointerToY的值,即y的地址
fmt.Println("**pointerToPointerToInt: ", **pointerToPointerToInt) // 这给出10,因为我们重定向两次才能得到y
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' 是相同的!")
}
if pointerToY == &y {
fmt.Println("'pointerToY == &y' 是相同的!")
}
if &pointerToY == pointerToPointerToInt {
fmt.Println("'&pointerToY == pointerToPointerToInt' 是相同的!")
}
if y == **pointerToPointerToInt {
fmt.Println("'y == **pointerToPointerToInt' 是相同的!")
}
if pointerToY == *pointerToPointerToInt {
fmt.Println("'pointerToY == *pointerToPointerToInt' 是相同的!")
}
}
希望对你有所帮助!
英文:
In your example above you defined u as type User, but not a pointer to a User. So you need the &u because the Decode function in the json package is expecting an address or pointer.
If you created the instance of User like this: u := new(User) it would be a pointer since the new function returns a pointer. You could also create a pointer to a user like this: var u *User. If you did either of those, you would have to take out the &
in the call to Decode for it to work.
Pointers are basically variables that hold addresses. When you put the & in front of a variable it returns the address. The * could be read as 'redirect of'. So when you create a pointer like this:
var x *int
This can be read as x will redirect to an int. And when you assign a value to x you would give it an address like this:
y := 10
x = &y
Where y is some int. So if you were to print out x, you would get the address of y, but if you printed out *x you would redirect to the what x points to which is y's value which is 10. If you were to print out &x, you would get the address of the pointer, x, itself.
If you tried to print out *y, which is just an int, not a pointer, it would throw an error because you would be redirecting with some value that is not an address to redirect to.
Run the below for some pointer fun:
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!")
}
}
Hope this helps!
答案2
得分: 16
我将引用一个聪明的人的话:
> & 在变量名前面用于检索存储该变量值的地址。该地址是指针将要存储的内容。
>
> * 在类型名前面,表示声明的变量将存储另一个该类型变量的地址(而不是该类型的值)。
>
> * 在指针类型的变量前面用于检索存储在给定地址的值。在Go语言中,这被称为解引用。
来源:http://piotrzurek.net/2013/09/20/pointers-in-go.html
英文:
I will quote one smart dude:
> & in front of variable name is used to retrieve the address of where
> this variable’s value is stored. That address is what the pointer is
> going to store.
>
> * in front of a type name, means that the declared variable will store an address of another variable of that type (not a value of that
> type).
>
> * in front of a variable of pointer type is used to retrieve a value stored at given address. In Go speak this is called dereferencing.
source: http://piotrzurek.net/2013/09/20/pointers-in-go.html
答案3
得分: 3
一个简单的示例展示了代码的执行顺序。
import (
"fmt"
)
func main() {
x := 0
fmt.Println("步骤 1", x)
foo(&x)
fmt.Println("步骤 4", x)
}
func foo(y *int) {
fmt.Println("步骤 2", *y)
*y = 100
fmt.Println("步骤 3", *y)
}
步骤 结果
1 0
2 0
3 100
4 100
英文:
A simple example showing the code execution sequence.
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
*/
答案4
得分: 2
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的地址(使用pointerToY): ", pointerToY)
y = 4
fmt.Println("====================================================")
fmt.Println("y值改变后的地址: ", pointerToY)
fmt.Println("使用pointer访问y的值(值已改变): ", *pointerToY)
fmt.Println("y值改变后的x的值: ", x)
}
输出结果:
y: 10
y的地址(使用pointerToY): 0x414020
====================================================
y值改变后的地址: 0x414020
使用pointer访问y的值(值已改变): 4
y值改变后的x的值: 10
如我们所见,值可能会改变,但address
(&
)保持不变,因此pointer
(*
)指向address
的值。
在上面的示例中,
pointerToY
保存指向y
的address
的指针。x
保存我们使用pointer
传递给它的address
的值。- 在更改
y
的值后,x
仍然为10
,但如果我们尝试使用指向address
的pointer
(pointerToY)访问该值,我们会得到4
。
英文:
pointer
is used to point towards address
and it stores the memory address
Adding one example to help understand pointer
vs 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)
}
>output
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
As we can see, the value might change but the address
(&
) remains same and so the pointer
(*
) points to the value of address
.
In above example,
pointerToY
holds the pointer to referaddress
ofy
.x
holds the value which we pass to it usingpointer
toaddress
ofy
.- After changing the value of
y
, thex
still has10
but if we try to access the value usingpointer
toaddress
(pointerToY) , we get4
答案5
得分: 1
对于这个答案,我将尝试用一个变量值来解释。指针也可以指向结构体的值。
&
返回一个指针,指向一个变量值。
*
读取指针所指向的变量值。
示例:
func zero(xPointer *int) {
*xPointer = 0
fmt.Println(*xPointer)
}
func main() {
x := 1
zero(&x)
fmt.Println(x) // x 的值为 0
}
英文:
For this answer I will try to explain it with a variable value. A pointer can point also to a struct value.
&
returns a pointer, which points to a variable value.
*
reads the variable value to which the pointer is pointing.
Example:
func zero(xPointer *int) {
*xPointer = 0
fmt.Println(*xPointer)
}
func main() {
x := 1
zero(&x)
fmt.Println(x) // x is 0
}
答案6
得分: 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)
没有返回类型,我们无法从该函数中获取任何增加后的值,但我们可以将一个位置(地址)发送给该函数,并告诉它将该位置上的值增加1,然后我们可以从main()
函数中访问该位置,完成我们的任务。
一个快速提示:在变量前面的*
表示存储在该变量中的内容,而在变量前面的&
表示该变量的内部地址。
英文:
I would like to explain the concept of pointers(*
and &
) with an example:
Think of an example where we want to increment a variable by 1
with help of a function.
package main
import (
"fmt"
)
func main() {
x := 7
fmt.Print(inc(x))
}
func inc(x int) int {
return x + 1
}
Explanation of above: We have a function func inc(x int) int
which takes an integer and returns an integer with performing an increment.
> Note: Kindly pay attention that func inc(x int) int
returns an int
, Now what happens if we do not have a return type with that
> function?? This is solved by the pointer.
Look at the below code:
package main
import (
"fmt"
)
func main() {
x := 7
inc(&x)
fmt.Print(x)
}
func inc(x *int) {
*x++
}
Explanation of the above code:
Now as our function func inc(x *int)
does not have a return type we cannot get any incremented value from this function but what we can do is that we can send a location(address) to this function and tell it to increment the value at this location by one and now we can access that location from inside main()
and our job is done.
A quick tip: *
in front of a variable means what is stored in that variable?? and &
in front of a variable means what is the internal address of that variable?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论