Light Version
Raw Text
package main import "fmt" func main() { a := 0 b := 0 // a and b's address that points to where they are located in memory. fmt.Printf("main: &a = %v &b = %v\n\n", &a, &b) /* Note that when we pass by value, the 'a' declared in foo()'s arguments has a different address than the 'a' variable declared in main(). Which means that we are actually passing in a copy of main()'s 'a' variable. Any changes made to the value of foo()'s 'a' will not change the value of main()'s a. */ fmt.Println("[pass by value]") fmt.Println("main: before foo(a), a =", a) foo(a) fmt.Println("main: after foo(a), a =", a) /* Note that when we pass by pointer, the VALUE of bar()'s argument bptr equals the address of main()'s b. Also note that the main()'s bptr address is different than the addresses of main()'s b and bar()'s bptr. This means that a pointer is just a integer data type that stores an address in memory as it's value. When passing a pointer into a function, instead of passing in a copy of the variable being pointed to, we pass in a copy of the pointer itself. The new pointer still points to the same variable because the pointer's value (the variable's address) doesnt change. Since a pointer's value is only an integer representing the address of a variable in memory we cant directly modify the value of the variable being pointed at, by modifying the pointer's value. For example, lets say we wanted to increment variable 'b' (b+=1). If we tried, b := 0 bptr := &b // bptr == 0x01000008 bptr++ fmt.Println(b, bptr) // b == 0, bptr == 0x01000012 the value of b wont be incremented when 'bptr++' is called. What actually happens is that the value stored in bptr (the address bptr is currently pointing at) will be incremented to point to a new contigious block of memory. [NOTE: Unlike C/C++, developers arent actually allowed to directly modify the value of a pointer using arithmetic in go. Pointer arithmetic is considered an unsafe language feature, therefore developers must use go's "unsafe" pkg to manipulate a pointer's value.] In go and many other C-like language, accessing the variable through one of its pointers requires dereferencing the pointer by prefixing the dereference operator ('*') onto the pointer's identifier (e.g '*bptr'). In computer science terms this is called indirection. [NOTE: In C/C++/Go/etc, The asterisk symbol ('*') has several semantical meanings depending on the context in which it is used. Most developers will be familiar with it's use as the multiplication operator. However, for developers unfamiliar with C-style pointer syntax, the asterisk is a notoriously common source of confusion when first learning about pointers. I assume the reason for this confusion stems from the fact that the asterisk is not only used to dereferences a pointer, but to specify a pointer type as well. The confusion is only made much worse when the address-of operator ('&') and pointer pointers (i.e. xptr_ptr => xptr => x) are thrown in the mix. For example, check out this function literal. func(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) } Despite only being one line of code, it's not uncommon for even an experienced go developer to require a few moments to fully digest whats going on the first time they stumble upon code like this. I assume most developers, who are still new to pointers, will find code like this to be intimidating and very difficult to conceptually visualize whats going on semantically. If you, the reader of this blog post, are struggling to understand what this code does. I recommend taking it slow and using the language's spec as a codex to decipher what is going on. Here is code example to help point you in the right direction. http://play.golang.org/p/myunEgQPRG] */ bptr := &b fmt.Printf("\nmain: bptr = %v (aka &b), &bptr = %v, *bptr (aka b) = %v \n\n", bptr, &bptr, *bptr) fmt.Println("[pass by pointer]") fmt.Println("main: before bar(bptr), b =", b) bar(bptr) fmt.Println("main: after bar(bptr), b =", b) /* To be continued.... */ } func foo(a int) { fmt.Printf("foo: a = %v, &a = %v, \n", a, &a) fmt.Println("foo: a++") a++ fmt.Printf("foo: a = %v, &a = %v, \n", a, &a) } func bar(bptr *int) { fmt.Printf("bar: bptr = %v, &bptr = %v, *bptr (aka b) = %v \n", bptr, &bptr, *bptr) fmt.Println("bar: *bptr++") *bptr++ fmt.Printf("bar: bptr = %v, &bptr = %v, *bptr (aka b) = %v \n\n", bptr, &bptr, *bptr) }
No comments:
Post a Comment