Why keys are absent in map - dictionary

I created a map:
l := make(map[*A]string)
where A is:
type A struct{}
Then added key-values into it:
a1 := &A{}
a2 := &A{}
a3 := &A{}
l[a1] = "a1"
l[a2] = "a2"
l[a3] = "a3"
I expected to see all values ("a1", "a2", "a3") while doing range
for k, v := range l{
fmt.Println(k, v)
}
But I see only the last one.
Why that happens?
https://play.golang.org/p/GSdUWzExxLK

Because your struct has no fields, Go optimizes away all pointers to it to the same address, so you're using the same key every time. Give the struct a field (even if you never put a value in it) and you'll get your expected behavior.
Playground: https://play.golang.org/p/n-WUZ9wqpGJ
You can read more about empty structs (including this pointer behavior) on Dave Cheney's blog.
It's mentioned only briefly in the spec, under Sizes and Alignments, and is in fact the very last sentence in the spec:
A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.

This is because A is an empty structure. As it cannot change go always assigns it the same memory address. If you add a field to A it will start working:
type A struct{a string}
func main() {
a1 := A{}
a2 := A{}
l := make(map[*A]string)
l[&a1] = "a1"
l[&a2] = "a2"
for i, v := range l{
i := i
fmt.Println(&i, v)
}
}
Prints:
0x40e138 a1
0x40e150 a2
https://play.golang.org/p/hYzU73kbVPV
Dave Cheney goes into more depth here:
https://dave.cheney.net/2014/03/25/the-empty-struct

Related

Go determine number of word occurences on a string slice

Having a hard time trying to figure out how can I count the number of apps or words on a slice using the go-lang code I made.
Hoping someone could help me figure out how to count the number of occurence?
https://play.golang.org/p/KvgI-lCz_c6
package main
import (
"fmt"
)
func main() {
apps := []string{"one", "two", "three", "one", "four"}
fmt.Println("apps:", apps)
o := CountOccurence(apps)
fmt.Println("=== o: ", o)
}
func CountOccurence(apps []string) map[string]int {
dict := make(map[string]int)
for k, v := range apps {
fmt.Println(k, v)
dict[v] = k
}
// fmt.Println("=== dict: ", dict)
return dict
}
Outputs the following
apps: [one two three one four]
0 one
1 two
2 three
3 one
4 four
=== o: map[four:4 one:3 three:2 two:1]
PS: go strings.Count only counts a string, not a []string.
What you currently do is you gather the different elements and you assign their index to them. If a word occurs multiple times, the highest index will be assigned to it.
As you stated, you want to count the words. So instead of the index, assign 1 for new words (first occurrence), and if it's already in the map, increment its value by 1.
Since you can index a map with a non-existing key, in which case the result is the zero value of the value type of the map, which is 0 for int, it will tell you it was found 0 times (so far), so you don't even have to check if a key is already in there, just go ahead and increment it:
dict[v]++
So CountOccurrences() may look like this:
func CountOccurence(apps []string) map[string]int {
dict := make(map[string]int)
for _, v := range apps {
fmt.Println(v)
dict[v]++
}
return dict
}
Which will output (try it on the Go Playground):
apps: [one two three one four]
one
two
three
one
four
=== o: map[four:1 one:2 three:1 two:1]

go's big.Int underlying value mutates when value points to another instance

I have come across a bit of unexplained behavior of go's big.Int when pointing an instance of one big.Int to another.
I am knowledgeable that in order to set a value of a bit.Int's instance to another, one must use the Int.SetXXX setters, because they actually cause the underlying abs slice in big.Int to be copied to a newly allocated array. However, putting that aside for a moment, I'd like to know why the following behavior occurs.
Consider the following:
Wrong example (underlying value mutates):
func main() {
v1p := big.NewInt(1)
v2p := big.NewInt(2)
v1 := *v1p
v2 := *v2p
v2 = v1
v1.SetInt64(3)
fmt.Println(v1.Int64(), v2.Int64())
}
(run here: https://play.golang.org/p/WxAbmGdKG9b)
Correct example (value does not mutate):
func main() {
v1p := big.NewInt(1)
v2p := big.NewInt(2)
v1 := *v1p
v2 := *v2p
v2.Set(v1p)
v1.SetInt64(3)
fmt.Println(v1.Int64(), v2.Int64())
}
(run here: https://play.golang.org/p/16qsGhwHIWf)
If I understand correctly, the following should essentially demonstrate what happens in the wrong example:
func main() {
var a, b *int // analogous to the 2 big.Int pointers returned
c, d := 3, 3
a = &c // we set the pointers to point to something we can then dereference
b = &d
e := *a // e and f should now point to the values pointed to by the pointers
f := *b
// the rest is self-explanatory
e = f
c = 5
d = 4
fmt.Println(a, b, c, d, e, f)
}
(run here: https://play.golang.org/p/cx76bnmJhG7)
My only assumption is that somehow when copying the struct content onto v2 in the Wrong example, what happens is that abs slice does not get deep-copied but that the storage that it references is actually the same storage that the slice in v1 points to.
Is this really what happens? Is this the expected behavior according to the language spec too?
As pointed out by icza and Volker, since when dereferencing the big.Int pointer the actual value slice header struct is copied, pointing to the same underlying value, the resulting behavior is that the same underlying array gets referenced from multiple slices, resulting in one altering the other.

Very Confusing variable changes

http://play.golang.org/p/Vd3meom5VF
I have this code for some context free grammar in Go
And I am looking at this code so many times and still don't see any reason for the struct values to be changed. Could anybody see why the change like the following happens?
Rules:
S -> . [DP VP]
VP -> . [V DP]
VP -> . [V DP AdvP]
After I run some functions as in the line
or2 = append(or2, OstarCF([]QRS{q}, []string{"sees"}, g2.Nullables(), g2.ChainsTo(g2.Nullables()))...)
Somehow my struct value is changed... I don't know why...
Rules:
S -> . [VP VP]
VP -> . [DP DP]
VP -> . [AdvP AdvP AdvP]
This should have been same as above.
Rules:
S -> DP,VP
VP -> V,DP
VP -> V,DP,AdvP
or2 := []QRS{}
g2 := ToGrammar(cfg2)
fmt.Printf("%s\n", g2)
for _, rule := range g2.Rules {
q := QRS{
one: rule.Src,
two: []string{},
three: rule.Right,
}
or2 = append(or2, OstarCF([]QRS{q}, []string{"sees"}, g2.Nullables(), g2.ChainsTo(g2.Nullables()))...)
}
fmt.Printf("%s\n", g2)
As you see, I do not use any pointer the variable rule, and they are only used to instantiate another struct value, but how come the original struct field rule has changed? The function OstarCF does not do anything about this field rule
func OstarCF(Qs []QRS, R []string, nD map[string]bool, cD map[string][]string) []QRS {
symbols := []string{}
for _, r := range R {
symbols = append(symbols, cD[r]...)
}
product := []QRS{}
for _, Q := range Qs {
a := Q.one
b := Q.two
c := Q.three
if len(c) > 0 && CheckStr(c[0], symbols) {
b = append(b, c[0])
np := QRS{
one: a,
two: b,
three: c[1:],
}
product = append(product, np)
for len(np.three) > 0 && nD[np.three[0]] == true {
np.two = append(np.two, np.three[0])
np = QRS{
one: np.one,
two: np.two,
three: np.three[1:],
}
product = append(product, np)
}
}
}
return product
}
The original Rules field changes because pointers and slices (which are references as well) are used.
Before calling OstarCF, the ChainsTo method is called. It uses the grammar object by value, so a copy is done, but the Rules field is a slice of pointers on Rules. So when this field is copied, it still points to the data of the original object.
Then, in method ChainsTo, there is a loop on the Rules field. It copies the Right field which is a slice of strings (so it still points to data of the original object):
rhs := rule.Right
Finally, a ns variable is declared by slicing rhs:
ns := rhs[:i]
ns = append(ns, rhs[i+1:]...)
At this stage, the ns variable still points to the buffer containing the slice of strings of the original object. Initially, i=0, so ns is an empty slice reusing the buffer. When items are appended, they replace the original data.
That's why your data are changed.
You can fix this problem by explicitly making a copy, for instance by replacing the above lines by:
ns := make( []string, 0, len(rhs) )
ns = append( ns, rhs[:i]...)
ns = append( ns, rhs[i+1:]...)
Go slices have replaced C pointer arithmetic, but they can be almost as dangerous/misleading in some cases.

Set slice index using reflect in Go

I'm in Go, working with a reflect.Value representation of a slice. I have the following:
slice := reflect.MakeSlice(typ, len, cap)
If I want to get the ith value from slice, it's simple:
v := slice.Index(i) // returns a reflect.Value
However, I can't seem to find a way to set the ith value. reflect.Value has lots of setter methods, for example, if I had a map, m, the following is possible:
m.SetMapIndex(key, value) // key and value have type reflect.Value
But there doesn't seem to be an equivalent for slices. My one thought was that maybe the value returned from slice.Index(i) is actually a pointer somehow, so calling v := slice.Index(i); v.Set(newV) would work? I'm not sure. Ideas?
Figured it out! Turns out I posted this prematurely - my guess that slice.Index(0) returns a pointer was correct. In particular:
one := reflect.ValueOf(int(1))
slice := reflect.MakeSlice(reflect.TypeOf([]int{}), 1, 1)
v := slice.Index(0)
fmt.Println(v.Interface())
v.Set(one)
fmt.Println(v.Interface())
v = slice.Index(0)
fmt.Println(v.Interface())
prints:
0
1
1
(Here's runnable code on the go playground)
This might help:
n := val.Len()
if n >= val.Cap() {
ncap := 2 * n
if ncap < 4 {
ncap = 4
}
nval := reflect.MakeSlice(val.Type(), n, ncap)
reflect.Copy(nval, val)
val.Set(nval)
}
val.SetLen(n + 1)
// ...
val.Index(n).SetString("value") // Depends on type
Taken from a library I wrote a while back github.com/webconnex/xmlutil, specifically decode.go.

In Go how to get a slice of values from a map?

If I have a map m is there a better way of getting a slice of the values v than this?
package main
import (
"fmt"
)
func main() {
m := make(map[int]string)
m[1] = "a"
m[2] = "b"
m[3] = "c"
m[4] = "d"
// Can this be done better?
v := make([]string, len(m), len(m))
idx := 0
for _, value := range m {
v[idx] = value
idx++
}
fmt.Println(v)
}
Is there a built-in feature of a map? Is there a function in a Go package, or is this the only way to do this?
As an addition to jimt's post:
You may also use append rather than explicitly assigning the values to their indices:
m := make(map[int]string)
m[1] = "a"
m[2] = "b"
m[3] = "c"
m[4] = "d"
v := make([]string, 0, len(m))
for _, value := range m {
v = append(v, value)
}
Note that the length is zero (no elements present yet) but the capacity (allocated space) is initialized with the number of elements of m. This is done so append does not need to allocate memory each time the capacity of the slice v runs out.
You could also make the slice without the capacity value and let append allocate the memory for itself.
Unfortunately, no. There is no builtin way to do this.
As a side note, you can omit the capacity argument in your slice creation:
v := make([]string, len(m))
The capacity is implied to be the same as the length here.
Go 1.18
You can use maps.Values from the golang.org/x/exp package.
Values returns the values of the map m. The values will be in an indeterminate order.
func main() {
m := map[int]string{1: "a", 2: "b", 3: "c", 4: "d"}
v := maps.Values(m)
fmt.Println(v)
}
The package exp includes experimental code. The signatures may or may not change in the future, and may or may not be promoted to the standard library.
If you don't want to depend on an experimental package, you can easily implement it yourself. In fact, this code is a copy-paste from the exp package:
func Values[M ~map[K]V, K comparable, V any](m M) []V {
r := make([]V, 0, len(m))
for _, v := range m {
r = append(r, v)
}
return r
}
Not necessarily better, but the cleaner way to do this is by defining both the Slice LENGTH and CAPACITY like txs := make([]Tx, 0, len(txMap))
// Defines the Slice capacity to match the Map elements count
txs := make([]Tx, 0, len(txMap))
for _, tx := range txMap {
txs = append(txs, tx)
}
Full example:
package main
import (
"github.com/davecgh/go-spew/spew"
)
type Tx struct {
from string
to string
value uint64
}
func main() {
// Extra touch pre-defining the Map length to avoid reallocation
txMap := make(map[string]Tx, 3)
txMap["tx1"] = Tx{"andrej", "babayaga", 10}
txMap["tx2"] = Tx{"andrej", "babayaga", 20}
txMap["tx3"] = Tx{"andrej", "babayaga", 30}
txSlice := getTXsAsSlice(txMap)
spew.Dump(txSlice)
}
func getTXsAsSlice(txMap map[string]Tx) []Tx {
// Defines the Slice capacity to match the Map elements count
txs := make([]Tx, 0, len(txMap))
for _, tx := range txMap {
txs = append(txs, tx)
}
return txs
}
Simple solution but a lot of gotchas. Read this blog post for more details: https://web3.coach/golang-how-to-convert-map-to-slice-three-gotchas
As far as I'm currently aware, go doesn't have a way method for concatenation of strings/bytes in to a resulting string without making at least /two/ copies.
You currently have to grow a []byte since all string values are const, THEN you have to use the string builtin to have the language create a 'blessed' string object, which it will copy the buffer for since something somewhere could have a reference to the address backing the []byte.
If a []byte is suitable then you can gain a very slight lead over the bytes.Join function by making one allocation and doing the copy calls your self.
package main
import (
"fmt"
)
func main() {
m := make(map[int]string)
m[1] = "a" ; m[2] = "b" ; m[3] = "c" ; m[4] = "d"
ip := 0
/* If the elements of m are not all of fixed length you must use a method like this;
* in that case also consider:
* bytes.Join() and/or
* strings.Join()
* They are likely preferable for maintainability over small performance change.
for _, v := range m {
ip += len(v)
}
*/
ip = len(m) * 1 // length of elements in m
r := make([]byte, ip, ip)
ip = 0
for _, v := range m {
ip += copy(r[ip:], v)
}
// r (return value) is currently a []byte, it mostly differs from 'string'
// in that it can be grown and has a different default fmt method.
fmt.Printf("%s\n", r)
}
As of 1.18, this is the best way:
https://stackoverflow.com/a/71635953/130427
Pre 1.18
You can use this maps package:
go get https://github.com/drgrib/maps
Then all you have to call is
values := maps.GetValuesIntString(m)
It's type-safe for that common map combination. You can generate other type-safe functions for any other type of map using the mapper tool in the same package.
Full disclosure: I am the creator of this package. I created it because I found myself rewriting these functions for map repeatedly.

Resources