Map as a method receiver - go

Does anyone know why map can be used as a value receiver, but when working with slices only the pointer receiver can be used? Why the map is changing after the method call?
Example for map:
package main
import (
"fmt"
)
type hashMap map[string]int
func (s hashMap) Add(k string, v int) {
s[k] = v
}
func main() {
var s hashMap
s = make(hashMap, 0)
fmt.Println(s)
s.Add("abc", 15)
fmt.Println(s)
}
Output:
map[]
map[abc:15]
Example for slice:
package main
import (
"fmt"
)
type slice []int
func (s *slice) Add(v int) {
(*s) = append(*s, v)
}
func main() {
var s slice
s = make(slice, 0)
fmt.Println(s)
s.Add(15)
fmt.Println(s)
}
Output:
[]
[15]

A map variable, after make, is a pointer to the map header: *hmap. The map pointer is passed by value
// A header for a Go map.
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
// ../reflect/type.go. Don't change this structure without also changing that code!
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
A slice variable is a struct: slice. The slice struct is passed by value.
type slice struct {
array unsafe.Pointer
len int
cap int
}

Map is receiver type while struct is value type,Value type. Hence when you call using map value changes after function call.

Related

Sort 2D array of structs Golang

I want to create a consistent ordering for a 2D slice of structs, I am creating the 2D slice from a map so the order is always different.
My structs look like
// Hit contains the data for a hit.
type Hit struct {
Key string `json:"key"`
Data []Field `json:"data"`
}
// Hits stores a list of hits.
type Hits [][]Hit
I want to provide a consistent order for the contents of my Hits type.
I have tried:
func (c Hits) Len() int { return len(c) }
func (c Hits) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c Hits) Less(i, j int) bool { return strings.Compare(c[i][0].Key, c[j][0].Key) == -1 }
But the results still seem to come back in random order.
I was thinking of possibly hashing each item in the slice but thought there might be an easier option
The order of iteration over a map, because it's a hash table is rather indeterminate (it's not, really — insert items with the same keys in the same exact sequence into 2 maps and the order of iteration for each will be identical).
Assuming that your map is a map[string]Hit, to iterate it over in a determinate order, I would enumerate the set of keys in the map, sort that, and use that sorted set to enumerate the map.
Something like this:
package main
import (
"fmt"
"sort"
)
type Hit struct {
Key string `json:"key"`
Data []Field `json:"data"`
}
type Field struct {
Value string `json:"value"`
}
func main() {
var mapOfHits = getSomeHits()
var sortedHits = sortHits(mapOfHits)
for _, h := range sortedHits {
fmt.Println(h.Key)
}
}
func getSomeHits() map[string]Hit {
return make(map[string]Hit, 0)
}
func sortHits(m map[string]Hit) []Hit {
keys := make([]string, 0, len(m))
sorted := make([]Hit, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
sorted = append(sorted, m[k])
}
return sorted
}

which type's size is zero in slice of golang?

which type's size is zero in slice of golang?
When I read the source code of golang slice, I found a code et.size == 0. so I want to know which type's size is 0?
func growslice(et *_type, old slice, cap int) slice {
...
if et.size == 0 {
if cap < old.cap {
panic(errorString("growslice: cap out of range"))
}
return slice{unsafe.Pointer(&zerobase), old.len, cap}
}
...
}
The Go Programming Language Specification
Size and alignment guarantees
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.
For example,
package main
import (
"fmt"
"unsafe"
)
func main() {
type zero struct{}
fmt.Println(unsafe.Sizeof(zero{}))
slice := make([]zero, 7)
fmt.Printf("%d %v %p %p\n", len(slice), slice, &slice[0], &slice[len(slice)-1])
}
Playground: https://play.golang.org/p/pn8Rz0IorwD
Output:
0
7 [{} {} {} {} {} {} {}] 0x1c4c84 0x1c4c84

Freeing map of struct

I am working with a very large map of pointer to struct. It is growing over the lifetime of the program (I use it as a buffer) and I wrote a function that is supposed to reduce it size when it is called.
type S struct {
a uint32
b []uint32
}
s := make(map[uint32]*S)
for k, v := range s {
delete(s, k)
s[k] = &S{a: v.a}
}
I remove b from every element of the map, so I expected the size of the map in memory to shrink (b is a slice of length > 10). However the memory is not freed, why?
The size of the map value &S, a pointer, is the same irrespective of the capacity of slice b.
package main
import (
"fmt"
"unsafe"
)
type S struct {
a uint32
b []uint32
}
func main() {
size := unsafe.Sizeof(&S{})
fmt.Println(size)
size = unsafe.Sizeof(&S{b: make([]uint32, 10)})
fmt.Println(size)
s := make(map[uint32]*S)
for k, v := range s {
delete(s, k)
s[k] = &S{a: v.a}
}
}
Output:
8
8
A slice is represented internally by
type slice struct {
array unsafe.Pointer
len int
cap int
}
When you set &S{a: v.a} you set b to initial values: array to nil and len and cap to zero. The memory formerly occupied by the underlying array is returned to the garbage collector for reuse.
The map size is bounded to the maximum size it had at any point. Because you store pointers (map[uint32]*S) and not values the deleted objects will get garbage collected eventually but usually not immediately and that why you don’t see it in top/htop like monitors.
The runtime is clever enough and reserves memory for future use if the system is not under pressure or low on resources.
See https://stackoverflow.com/a/49963553/1199408 to understand more about memory.
In your example you don't need to call delete. You will achieve what you want just by clearing the slice in the struct.
type S struct {
a uint32
b []uint32
}
s := make(map[uint32]*S)
for k, v := range s {
v.b = []uint32{}
}

How to pass an accumulator to a recursive func?

(I'm new to Go.)
I am working on this leetcode problem: https://leetcode.com/problems/pascals-triangle/
package main
import "fmt"
func main() {
arrRes := [][]int{}
gen(5, arrRes)
fmt.Println(arrRes)
}
func gen(numRows int, arrRes [][]int) {
build(numRows, 0, arrRes)
}
func build(n int, level int, arrRes [][]int) {
if(n == level) {
return
}
arr := []int{}
if level == 0 {
arr = append(arr, 1)
} else if level == 1 {
arr = append(arr, 1, 1)
} else {
// get it out
tmp := arrRes[level-1]
arr = comb(tmp)
}
arrRes = append(arrRes, arr)
build(n, level+1, arrRes)
}
func comb(arr []int) []int{
// arr type init
tmpArr := []int{1}
for i:=1; i<len(arr); i++ {
sum := arr[i-1] + arr[i]
tmpArr = append(tmpArr, sum)
}
// go use val, not ref
tmpArr = append(tmpArr, 1)
return tmpArr;
}
I want to define an accumulated variable arrRes := [][]int{} and keep passing into the recursive function. I think Go is pass-by-value instead of pass-by-reference. Is there a way to keep this pattern?
I've got two alternative methods:
passing a global var.
pass a 2D array into the func then return the new 2D array.
https://github.com/kenpeter/go_tri/blob/master/tri_global.go
https://github.com/kenpeter/go_tri/blob/master/tri.go
A slice is (basically) three things: a length, a capacity, and a pointer to an underlying array. Everything in Go is pass-by-value, so when you pass a slice to a function you are passing its current length, current capacity, and the memory address of the pointer. Changes made to length and capacity inside the function are made to a copy, and will not affect the length and capacity of the slice that was passed as an argument in the function call.
Printing a slice doesn't print its underlying array, it prints the part of the underlying array that is visible in the slice (which could be none of it if len = 0), based on (1) the pointer to the first element in the underlying array that's supposed to be visible to the slice; and (2) the length in the slice variable.
If you are modifying the length or capacity of a slice inside a function and you want those changes to be visible outside the function, you can either return the slice to update the context outside the function, like append does:
numbers := append(numbers, 27)
Or you can pass in a pointer to a slice:
func ChangeNumbersLenOrCap(numbers *[]int) {
// make your changes, no return value required
}
For your program, it looks like you could get away with a pointer to a slice of int slices:
var arrRes *[][]int
...because you're not modifying the int slice across another function boundary. Some programs would need a pointer to a slice of pointers to int slices:
var arrRes *[]*[]int
Here are some simple edits to get you started:
arrRes := [][]int{}
gen(5, &arrRes)
fmt.Println(arrRes)
}
func gen(numRows int, arrRes *[][]int) {
// ...
func build(n int, level int, arrRes *[][]int) {
// ...
tmp := *arrRes[level-1]
// ...
*arrRes = append(*arrRes, arr)
build(n, level+1, arrRes)

How to implement BitSet with Go?

I didn't find a BitSet package in Go, so I tried to implement it.
I'd like to use a array of uint64 to store the bits.
I need the number of bits to allocate the uint64 array.
With Java, I can define a constructor that takes an integer.
While Go doesn't provide constructor, how can I properly initialize
the BitSet 'object' when user call new()?
Go's standard big.Int can be used as a bit set:
package main
import (
"fmt"
"math/big"
)
func main() {
var bits big.Int
for i := 1000; i < 2000; i++ {
bits.SetBit(&bits, i, 1)
}
for i := 0; i < 10000; i++ {
if bits.Bit(i) != 0 {
fmt.Println(i)
}
}
}
https://play.golang.org/p/xbIK-boouqC
Declare bitSet as a private struct:
type bitSet struct {
len int
array []uint64
}
Expose the interface BitSet:
type BitSet interface {
Has(pos int) bool
Add(pos int) bool
Len() int
}
Also expose a function NewBitSet:
func NewBitSet(len int) BitSet {
return &bitSet{len, make(uint64, (len+7) / 8) }
}
This is a Go way for encapsulation: share an interface, not the implementation.
If you use a []uint64 slice to store your data, then the zero slice could function as the empty BitSet. In fact appending to a nil slice allocates a new array for you, although the Language Specification doesn't appear to guarantee that. With that kind of setup, new(BitSet) would be immediately usable. Example:
bitset.go:
package bitset
const size = 64
type bits uint64
// BitSet is a set of bits that can be set, cleared and queried.
type BitSet []bits
// Set ensures that the given bit is set in the BitSet.
func (s *BitSet) Set(i uint) {
if len(*s) < int(i/size+1) {
r := make([]bits, i/size+1)
copy(r, *s)
*s = r
}
(*s)[i/size] |= 1 << (i % size)
}
// Clear ensures that the given bit is cleared (not set) in the BitSet.
func (s *BitSet) Clear(i uint) {
if len(*s) >= int(i/size+1) {
(*s)[i/size] &^= 1 << (i % size)
}
}
// IsSet returns true if the given bit is set, false if it is cleared.
func (s *BitSet) IsSet(i uint) bool {
return (*s)[i/size]&(1<<(i%size)) != 0
}
bitset_test.go:
package bitset
import "fmt"
func ExampleBitSet() {
s := new(BitSet)
s.Set(13)
s.Set(45)
s.Clear(13)
fmt.Printf("s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n",
s.IsSet(13), s.IsSet(45), s.IsSet(30))
// Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}
The short answer is, you can't properly initialize the BitSet object when a client calls new().
The best thing you can do is make it so that your BitSet's zero value is valid. This is what types like list.List, sync.Mutex, and big.Int do. This way you know that it's impossible for a client to get an invalid value.
The next best thing you can do is create a constuctor-like function (named NewBitSet in this case) and expect clients to call it.

Resources