func Test(t *testing.T) {
a1 := 5
a2 := 6
a3 := 7
p1 := &a1
p2 := &a2
p3 := &a3
s := make([]int, 0)
s = append(s, *p1, *p2, *p3)
a1 = 8
if s[0] != 8 {
t.Fail()
}
}
Why does the test fail?
I don't have much experience in Go, but I thought that two variables can have the same value that is stored in one memory address. But what I see from the test bellow it's not correct.
Doesn't it mean that if I want to change some variable from different places in my program I have to store it in variable and then use only pointers everywhere in the code?
This has nothing to do with the use of slice types per se, and everything to do with the fact that you're storing int values.
It is true that p1, p2, and p3 have type *int (pointer to int). They point to a1, a2, and a3 respectively (and those three have type int, due to the default type rules, which dictate that the untyped constants 5, 6, and 7 become int here). But this means that *p1, *p2, and *p3 have type int. So:
s = append(s, *p1, *p2, *p3)
does the same thing as:
s = append(s, 5, 6, 7)
would do (given that *p1 is 5, and so on, which we can see by just looking at the code—none of the a variables have changed yet).
You then change variable a1 to 8. So *p1 is also now 8, but you've built your slice out of the three values 5, 6, and 7, and those values are not changed here. If you print *p1, you will see that it is now 8. If you assign to *p2, then print a2, you will see that a2 is updated by assigning to *p2.
As zerkms noted in a comment, if you had built your slice out of type *int and made s[0] point to a1, then changing a1 would also change *s[0]. Similarly, changing *s[1] would change a2. You didn't do that, though, so they don't. Again, though, it's not a matter of whether you use a slice here, but rather whether the variables in question are pointers, and if so, what they point-to1 at the time you use their values.
1I hyphenated this to avoid the urge to write "to what they point". :-)
Related
I'm working my way through this "Tour of Go" and I'm doing this exercise here. I originally wrote the answer like this:
func Pic(dx, dy int) [][]uint8 {
outer := make([][]uint8, dy)
inner := make([]uint8, dx)
for y, _ := range outer {
for x, _ := range inner {
inner[x] = x^y // this is one of the image functions they give
}
outer[y] = inner
}
return outer
}
I thought this should work, but when I run Pic(5,5) I get:
[[0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16] [0 4 8 12 16]]
Not right, obviously.
So, I finally figured out that I needed to move my inner := make([]uint8, dx) declaration inside of the first loop like so:
func Pic(dx, dy int) [][]uint8 {
outer := make([][]uint8, dy)
for y, _ := range outer {
inner := make([]uint8, dx)
for x, _ := range inner {
inner[x] = x^y // this is one of the image functions they give
}
outer[y] = inner
}
return outer
}
and now Pic(5,5) gives me the correct answer:
[[0 0 0 0 0] [0 1 2 3 4] [0 2 4 6 8] [0 3 6 9 12] [0 4 8 12 16]]
What's happening here? I think this has something to do with pointers or something, but I want to be sure I really understand what's going on. Obviously, in the first example, each time I reassigned something new to inner the values in outer that previously had inner assigned to them changed as well.
But what happens in the second example? Each time we go through the range outer loop the inner variable gets re-declared, but what happens to the values of outer that previously had inner assigned to them? Are they now somehow "cut off" and only exist as copies?
I'm mainly confused because the assignment line outer[y] = inner doesn't change in either example, so I don't understand the mechanics of how in one of them it assigns a copy of the value and in the other it assigns what I would think of as a pointer.
In the first case, you never "reassigned something new to inner". You created one slice of uint8, called inner, which you filled with values (overwriting those values several times), and you made every element of outer contain a copy of inner. But remember, a slice is only a view into an array that exists somewhere (in your case, the backing array is created anonymously by make). Copying a slice doesn't copy the values in the array, it just copies the slice header, meaning there are now multiple views onto the same storage (this is fine, and safe).
In the second case, you called make for every row of outer, so five different backing arrays were created, with inner pointing into a different one each time. This time, when you assigned inner to an element of outer, you got five genuinely different slice headers, instead of five copies of the same one.
In short: a slice is a value, but it's a value that contains a pointer. The pointer might point to an array that has a name, or it might point to an entirely anonymous array. There's nothing to worry about; Go will make sure that anything that is pointed-to stays alive.
First, consider this:
inner := make([]uint8, dx)
This statement allocates an array large enough to hold dx elements, creates a slice from it, and stores that slice in the variable inner. A slice contains three values: a pointer to the underlying array, capacity of that array, and the length of the slice. So inner contains a pointer to the actual data.
When you redeclare and assign inner in the for loop, a new array is created to store the data, inner becomes a slice pointing to that array, and then you fill out the individual elements of inner. Then you assign inner to an element of outer, and that element of outer now gets that slice, pointing to the initialized data. In the next iteration, a new array is created, inner is assigned to it, etc.
So it's got to do with pointers, in particular, the fact that a slice contains a pointer to the underlying array, and that when you assign a variable to a slice, that variable is assigned three values, the pointer to array, length, and capacity,
There are two problems I don't understand.
The first one is that one slice variable is assigned to another variable, and it is found that the address of the new variable is inconsistent with that of the variable. My understanding is that slice shares memory, and their addresses are the same according to the principle.
the Second is then when the slice variable is insufficient in capacity, the memory address does not change after the append operation. It should change according to the principle, because the memory address will be newly allocated when the capacity is insufficient.
I would appreciate your comments.
var a = []int{1,2,3}
fmt.Printf("%p\n",&a)
b:=a
fmt.Printf("%p\n",&b) 1)、the first question
b=append(b,0)
fmt.Printf("%p\n",&b) 2)、the second question
fmt.Println(a)
fmt.Println(b)
run result is:
0xc04204c3a0
0xc04204c3e0
0xc04204c3e0
[1 2 3]
[1 2 3 0]
A slice value contains a pointer to the backing array, length and capacity. See Go Slices: usage and internals for the details.
Here's some commentary on the code in the question:
var a = []int{1, 2, 3}
// Print address of variable a
fmt.Printf("%p\n", &a)
b := a
// Print address of variable b. The variable a and b
// have different addresses.
fmt.Printf("%p\n", &b)
b = append(b, 0)
// Print address of variable b. Append did not change
// the address of the variable b.
fmt.Printf("%p\n", &b)
Print the address of the first slice element to get the results you expect.
var a = []int{1, 2, 3}
// Print address of a's first element
fmt.Printf("%p\n", &a[0])
b := a
// Print address of b's first element. This prints
// same value as previous because a and b share a backing
// array.
fmt.Printf("%p\n", &b[0])
b = append(b, 0)
// Print address of b's first element. This prints a
// different value from previous because append allocated
// a new backing array.
fmt.Printf("%p\n", &b[0])
// create a new slice struct which contains length, capacity and the underlying array.
// len(a)=3, cap(a)=3
var a = []int{1,2,3}
// `&a` means the pointer to slice struct
fmt.Printf("%p\n",&a)
// `b` is another newly created variable of slice struct, so `&b` differs from `&a`,
// but they share the same underlying array.
// len(b)=3, cap(b)=3
b := a
// the underlying array of `b` has been extended, and been newly allocated.
// but the pointer of `b` remains.
// len(b)=4, cap(b)=6
b = append(b, 0)
Hope that these comments can help you
I found this in some code:
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], prv)
What does [:] mean ?
If this is the full slice of the array, why not to pass the array itself? What kind of coding style is this, I wonder...
In go, Arrays and Slices are slightly different and cannot be used interchangeably; however, you can make a slice from an array easily using the [:] operator.
This article explains in detail - Go Slices: Usage and Internals.
See also the Slice Expressions section of The Go Programming Language Specification.
In a nutshell, the [:] operator allows you to create a slice from an array, optionally using start and end bounds. For example:
a := [4]int{1, 2, 3, 4} // "a" has type [4]int (array of 4 ints)
x := a[:] // "x" has type []int (slice of ints) and length 4
y := a[:2] // "y" has type []int, length 2, values {1, 2}
z := a[2:] // "z" has type []int, length 2, values {3, 4}
m := a[1:3] // "m" has type []int, length 2, values {2, 3}
Presumably the reason for this distinction is for an extra measure of type safety. That is, length is a formal part of an array type (e.g. [4]int is an array of four ints and a different size is a different type) whereas slices can have any length, including zero. So if you want the safety of a known-length sequence then use an Array, otherwise use a Slice for convenience.
GO MASTERs! could you advise?
with make([]int,len,cap), does GO allow array initialization at the same time to declaration?
myArray := make([]int, 3, 10){1,2,3}
I see cap(myArray) has changed as same to len(myArray) in the below case. What is fundamental behind?
<ex>
myArray := make([]int, 3, 10)
myArray = []int{1,2,3}
fmt.Println("len:"len(myArray),", cap:",cap(myArray))
len:3, cap:3
Why cap(myArray) is 3 instead of 10 as I declaration?
I initialized individual element directly. And, it works as I wanted
<ex>
myArray := make([]int, 3, 10)
myArray[0] = 1
myArray[1] = 2
myArray[2] = 3
fmt.Println("len:"len(myArray),", cap:",cap(myArray))
len:3, cap:10
I believe you're getting this result because in the first example you declare a slice with a length of 3 and a cap of 10. However, in the following statement you assign a completely different slice to that variable. Since the slice your assigning was declared/initialized using 'composite-literal' syntax and it has only 3 items, that is the capacity it is initialized with. In your second example, you assign values to each index of the slice you created with make, retaining the length and capacity properties.
To try and give more clarification... In C# or Java or C++ this would be like doing something like this;
List<string> myStrings = new List<string>();
myStrings.Add("A string");
myStrings = new List<string>();
As you might assume, after assigning a new list to the myStrings variable the old list is lost. So to give the simple answer, you're not just overwriting the cap, you're overwriting the whole slice. The value you have in your assignment that overwrites it, causes a slice to be created with a cap of 3 which is why you get that result.
So there's a few things at play here. I would strongly recommend the goblog's explanation of this: https://blog.golang.org/slices (go down to the section labeled Capacity). Also, just a (tiny) bit of semantics, but those are actually slices, not arrays :)
To get to the point, when you first declared your slice, you had a len of 3 and a capacity of 10. No problem with that. But then you redeclare myArray, and set it to be []int{1,2,3}. No problems there either, this is valid.
The problem comes when you expected your previous len/cap to remain the same; your slice is just a pointer to some space in memory. So you've now changed your underlying pointer (see the goblog). The capacity and length of the slice is now changed as well (to the default-- again, see the goblog). You can see the same changing of len/cap if you were to add more elements:
myArray := make([]int, 3, 10)
fmt.Println("len:"len(myArray),", cap:",cap(myArray)) // len: 3 cap: 10
myArray := []int{1, 2, 3}
fmt.Println("len:", len(myArray), "cap:", cap(myArray)) // len: 3 cap: 3
myArray = append(myArray, 4)
fmt.Println("len:", len(myArray), "cap:", cap(myArray)) // len: 4 cap: 8; automatically increases the cap
I'm just getting started with go and I've come across the following "problem".
I'm using a function which returns 4 unsigned 32 bit integers, and I was wondering what the best method to convert these values to 8 bit integers when I'm assigning them. (Or if it is possible). I have got it to work by assigning them to uint32, then converting them after that but I was wondering if there is a more concise way of doing it.
Example:
r, g, b, _ := image.At(x, y).RGBA() // ideally convert them at this stage
So Image.At returns uint32, but I would like r,g,b to be uint8
Thanks
Go has no syntax for what you want there. You're best bet is to just do it in the next line down.
rbig, gbig, bbig := image.At(x, y).RGBA()
r, g, b := uint8(rbig), uint8(gbig), uint8(bbig)
If that really annoys you though then just make a helper function
func convert(i, j, k, _ uint32) (uint8, uint8, uint8) { return uint8(i), uint8(j), uint8(k) }
r, g, b := convert(image.At(x, y).RGBA())
Still a minimum of two lines but you can reuse the function anywhere you need it and the call site might look a little cleaner to you.