Suppose I have maps of different types, among them of bools and of pointers and want to pass them to some function in single way:
type Blah struct {
name string
}
var mapBlah map[string]*Blah = make(map[string]*Blah)
var mapBool map[string]bool = make(map[string]bool)
func joinKeys(m map[string]interface{}) string {
// returns strings.Join(keys of map)
}
I seemingly can't pass these maps into this function (example). How can this be done properly, or
why it can't be done if I'm missing something, please?
When you already know the types, I think switching over types will be beneficial like follows.
package main
import (
"fmt"
"strings"
)
type Blah struct {
name string
}
var mapBlah map[string]*Blah = make(map[string]*Blah)
var mapBool map[string]bool = make(map[string]bool)
func joinKeys(m interface{}) string {
var a []string
switch v := m.(type) {
case map[string]*Blah:
for k, _ := range v {
a = append(a, k)
}
case map[string]bool:
for k, _ := range v {
a = append(a, k)
}
default:
}
return strings.Join(a, ",")
}
func main() {
mapBlah["1B"] = &Blah{name: "first"}
mapBlah["2B"] = &Blah{name: "second"}
fmt.Println(joinKeys(mapBlah))
mapBool["1Bool"] = true
fmt.Println(joinKeys(mapBool))
}
For more dynamic way with some performance tradeoffs reflection is way to go.
Python's ChainMap enables you to chain together several maps such that a lookup searches all of the maps in sequence until a matching key is found. Here is one of many articles about it:
https://dzone.com/articles/python-201-what-is-a-chainmap
And the official documentation:
https://docs.python.org/3/library/collections.html
Does anyone know of any existing equivalent package written in Go? I've so far been unable to find one, and would like to avoid re-inventing the wheel if one does exist.
There's not package but it's fairly simple to implement something similar:
Let's do it with a map[string]interface{}
package main
import (
"reflect"
"testing"
)
type ChainMap struct {
Map map[string]interface{}
maps []map[string]interface{}
}
func NewChainMap(maps ...map[string]interface{}) ChainMap {
if len(maps) == 0 {
return ChainMap{
Map: make(map[string]interface{}, 0),
maps: maps,
}
}
r := make(map[string]interface{}, len(maps[0]))
for i := len(maps) - 1; i >= 0; i-- {
m := maps[i]
for k, v := range m {
r[k] = v
}
}
return ChainMap{
Map: r,
maps: maps,
}
}
func (c ChainMap) Parents() ChainMap {
if len(c.maps) < 2 {
return c
}
return NewChainMap(c.maps[1:]...)
}
A small test:
func TestChainMap(t *testing.T) {
var m = NewChainMap(
map[string]interface{}{
"foo": "bar",
},
map[string]interface{}{
"foo": "baz",
"hello": "world",
},
map[string]interface{}{
"foo": "baw",
},
)
if !reflect.DeepEqual(
m.Map,
map[string]interface{}{
"foo": "bar",
"hello": "world",
},
) {
t.Fail()
}
if !reflect.DeepEqual(
m.Parents().Map,
map[string]interface{}{
"foo": "baz",
"hello": "world",
},
) {
t.Fail()
}
}
I eventually found an implementation buried in the bigkevmcd/go-configparser package: https://github.com/bigkevmcd/go-configparser/blob/master/chainmap/chainmap.go
The upside of this one is that it uses the original maps for storage, so does the right thing if one of them is updated later; this makes it work more like the original python version. The downside is that the caller needs to call Get() and Len() functions rather than simply using the object as a normal map.
package chainmap
type Dict map[string]string
type ChainMap struct {
maps []Dict
}
func New(dicts ...Dict) *ChainMap {
chainMap := &ChainMap{
maps: make([]Dict, 0),
}
for _, dict := range dicts {
chainMap.maps = append(chainMap.maps, dict)
}
return chainMap
}
func (c *ChainMap) Len() int {
return len(c.maps)
}
func (c *ChainMap) Get(key string) string {
var value string
for _, dict := range c.maps {
if result, present := dict[key]; present {
value = result
}
}
return value
}
I want to add a few helper methods attached onto a slice.
So I created a type which is of []*MyType
Is there any way to add to that slice of MyTypes? append will not recognise the slice.
package main
import "fmt"
type MyType struct{
Name string
Something string
}
type MyTypes []*MyType
func NewMyTypes(myTypes ...*MyType)*MyTypes{
var s MyTypes = myTypes
return &s
}
//example of a method I want to be able to add to a slice
func(m MyTypes) Key() string{
var result string
for _,i := range m{
result += i.Name + ":"
}
return result
}
func main() {
mytype1 ,mytype2 := MyType{Name:"Joe", Something: "Foo"}, MyType{Name:"PeggySue", Something: "Bar"}
myTypes:= NewMyTypes(&mytype1,&mytype2)
//cant use it as a slice sadface
//myTypes = append(myTypes,&MyType{Name:"Random", Something: "asdhf"})
fmt.Println(myTypes.Key())
}
I don't want to wrap it in another type and name the param even though I'm sorta doing it.. Because of json marshalling will probably be different
What would be the way to add to the MyTypes slice?
I really want to just be able to add a method to a slice so it can implement a specific interface and not effect the marshalling.. Is there a different better way?
Thanks
Update: This answer once contained two ways to solve the problem: my somewhat clunky way, the DaveC's more elegant way. Here's his more elegant way:
package main
import (
"fmt"
"strings"
)
type MyType struct {
Name string
Something string
}
type MyTypes []*MyType
func NewMyTypes(myTypes ...*MyType) MyTypes {
return myTypes
}
//example of a method I want to be able to add to a slice
func (m MyTypes) Names() []string {
names := make([]string, 0, len(m))
for _, v := range m {
names = append(names, v.Name)
}
return names
}
func main() {
mytype1, mytype2 := MyType{Name: "Joe", Something: "Foo"}, MyType{Name: "PeggySue", Something: "Bar"}
myTypes := NewMyTypes(&mytype1, &mytype2)
myTypes = append(myTypes, &MyType{Name: "Random", Something: "asdhf"})
fmt.Println(strings.Join(myTypes.Names(), ":"))
}
Playground: https://play.golang.org/p/FxsUo1vu6L
Basically, the only way (that I know of) to iterate through the values of the fields of a struct is like this:
type Example struct {
a_number uint32
a_string string
}
//...
r := &Example{(2 << 31) - 1, "...."}:
for _, d:= range []interface{}{ r.a_number, r.a_string, } {
//do something with the d
}
I was wondering, if there's a better and more versatile way of achieving []interface{}{ r.a_number, r.a_string, }, so I don't need to list each parameter individually, or alternatively, is there a better way to loop through a struct?
I tried to look through the reflect package, but I hit a wall, because I'm not sure what to do once I retrieve reflect.ValueOf(*r).Field(0).
Thanks!
After you've retrieved the reflect.Value of the field by using Field(i) you can get a
interface value from it by calling Interface(). Said interface value then represents the
value of the field.
There is no function to convert the value of the field to a concrete type as there are,
as you may know, no generics in go. Thus, there is no function with the signature GetValue() T
with T being the type of that field (which changes of course, depending on the field).
The closest you can achieve in go is GetValue() interface{} and this is exactly what reflect.Value.Interface()
offers.
The following code illustrates how to get the values of each exported field in a struct
using reflection (play):
import (
"fmt"
"reflect"
)
func main() {
x := struct{Foo string; Bar int }{"foo", 2}
v := reflect.ValueOf(x)
values := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
values[i] = v.Field(i).Interface()
}
fmt.Println(values)
}
If you want to Iterate through the Fields and Values of a struct then you can use the below Go code as a reference.
package main
import (
"fmt"
"reflect"
)
type Student struct {
Fname string
Lname string
City string
Mobile int64
}
func main() {
s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
v := reflect.ValueOf(s)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
}
}
Run in playground
Note: If the Fields in your struct are not exported then the v.Field(i).Interface() will give panic panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.
Go 1.17 (Q3 2021) should add a new option, through commit 009bfea and CL 281233, fixing issue 42782.
reflect: add VisibleFields function
When writing code that reflects over a struct type, it's a common requirement to know the full set of struct fields, including fields available due to embedding of anonymous members while excluding fields that are erased because they're at the same level as another field with the same name.
The logic to do this is not that complex, but it's a little subtle and easy to get wrong.
This CL adds a new reflect.VisibleFields() function to the reflect package that returns the full set of effective fields that apply in a given struct type.
fields := reflect.VisibleFields(typ)
for j, field := range fields {
...
}
Example,
type employeeDetails struct {
id int16
name string
designation string
}
func structIterator() {
fields := reflect.VisibleFields(reflect.TypeOf(struct{ employeeDetails }{}))
for _, field := range fields {
fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
}
}
Maybe too late :))) but there is another solution that you can find the key and value of structs and iterate over that
package main
import (
"fmt"
"reflect"
)
type person struct {
firsName string
lastName string
iceCream []string
}
func main() {
u := struct {
myMap map[int]int
mySlice []string
myPerson person
}{
myMap: map[int]int{1: 10, 2: 20},
mySlice: []string{"red", "green"},
myPerson: person{
firsName: "Esmaeil",
lastName: "Abedi",
iceCream: []string{"Vanilla", "chocolate"},
},
}
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Type().Field(i).Name)
fmt.Println("\t", v.Field(i))
}
}
and there is no *panic* for v.Field(i)
use this:
type x struct {
Id int
jsj int
}
func main() {
x2 := x{jsj: 10, Id: 5}
v := reflect.ValueOf(x2)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
}
====>10
====>5
Taking Chetan Kumar solution and in case you need to apply to a map[string]int
package main
import (
"fmt"
"reflect"
)
type BaseStats struct {
Hp int
HpMax int
Mp int
MpMax int
Strength int
Speed int
Intelligence int
}
type Stats struct {
Base map[string]int
Modifiers []string
}
func StatsCreate(stats BaseStats) Stats {
s := Stats{
Base: make(map[string]int),
}
//Iterate through the fields of a struct
v := reflect.ValueOf(stats)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
val := v.Field(i).Interface().(int)
s.Base[typeOfS.Field(i).Name] = val
}
return s
}
func (s Stats) GetBaseStat(id string) int {
return s.Base[id]
}
func main() {
m := StatsCreate(BaseStats{300, 300, 300, 300, 10, 10, 10})
fmt.Println(m.GetBaseStat("Hp"))
}
Use reflect package. First, get the type of variable with reflect.TypeOf and get numbers of elements with reflect.NumField.To obtain the values of the fields iteratively of a structure must reflect the variable and use the function rg.Elem().Field(i)
package main
import (
"fmt"
"reflect"
)
type Gopher struct {
Name string
Color string
Year int
}
func main() {
g := Gopher{Name: "AAA", Color: "BBBB", Year: 2021}
gtype := reflect.TypeOf(g)
numFields := gtype.NumField()
rg := reflect.ValueOf(&g)
for i := 0; i < numFields; i++ {
fmt.Println(rg.Elem().Field(i))
}
}
In Go, you can use the reflect package to iterate through the fields of a struct. The reflect package allows you to inspect the properties of values at runtime, including their type and value. Here's an example of how to iterate through the fields of a struct:
Go Playground
package main
import (
"fmt"
"reflect"
)
type Movie struct {
Name string
Year int
}
func main() {
p := Movie{"The Dark Knight", 2008}
val := reflect.ValueOf(p)
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
fmt.Printf("Field Name: %s, Field Value: %v\n", fieldType.Name, field.Interface())
}
}
Output:
Field Name: Name, Field Value: The Dark Knight
Field Name: Age, Field Value: 2008
Is there anything similar to a slice.contains(object) method in Go without having to do a search through each element in a slice?
Mostafa has already pointed out that such a method is trivial to write, and mkb gave you a hint to use the binary search from the sort package. But if you are going to do a lot of such contains checks, you might also consider using a map instead.
It's trivial to check if a specific map key exists by using the value, ok := yourmap[key] idiom. Since you aren't interested in the value, you might also create a map[string]struct{} for example. Using an empty struct{} here has the advantage that it doesn't require any additional space and Go's internal map type is optimized for that kind of values. Therefore, map[string] struct{} is a popular choice for sets in the Go world.
No, such method does not exist, but is trivial to write:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
You can use a map if that lookup is an important part of your code, but maps have cost too.
Starting with Go 1.18, you can use the slices package – specifically the generic Contains function:
https://pkg.go.dev/golang.org/x/exp/slices#Contains.
go get golang.org/x/exp/slices
import "golang.org/x/exp/slices"
things := []string{"foo", "bar", "baz"}
slices.Contains(things, "foo") // true
Note that since this is outside the stdlib as an experimental package, it is not bound to the Go 1 Compatibility Promise™ and may change before being formally added to the stdlib.
With Go 1.18+ we could use generics.
func Contains[T comparable](s []T, e T) bool {
for _, v := range s {
if v == e {
return true
}
}
return false
}
The sort package provides the building blocks if your slice is sorted or you are willing to sort it.
input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)
fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow")) // false
...
func contains(s []string, searchterm string) bool {
i := sort.SearchStrings(s, searchterm)
return i < len(s) && s[i] == searchterm
}
SearchString promises to return the index to insert x if x is not present (it could be len(a)), so a check of that reveals whether the string is contained the sorted slice.
Instead of using a slice, map may be a better solution.
simple example:
package main
import "fmt"
func contains(slice []string, item string) bool {
set := make(map[string]struct{}, len(slice))
for _, s := range slice {
set[s] = struct{}{}
}
_, ok := set[item]
return ok
}
func main() {
s := []string{"a", "b"}
s1 := "a"
fmt.Println(contains(s, s1))
}
http://play.golang.org/p/CEG6cu4JTf
If the slice is sorted, there is a binary search implemented in the sort package.
func Contain(target interface{}, list interface{}) (bool, int) {
if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
listvalue := reflect.ValueOf(list)
for i := 0; i < listvalue.Len(); i++ {
if target == listvalue.Index(i).Interface() {
return true, i
}
}
}
if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
}
return false, -1
}
I think map[x]bool is more useful than map[x]struct{}.
Indexing the map for an item that isn't present will return false. so instead of _, ok := m[X], you can just say m[X].
This makes it easy to nest inclusion tests in expressions.
You can use the reflect package to iterate over an interface whose concrete type is a slice:
func HasElem(s interface{}, elem interface{}) bool {
arrV := reflect.ValueOf(s)
if arrV.Kind() == reflect.Slice {
for i := 0; i < arrV.Len(); i++ {
// XXX - panics if slice element points to an unexported struct field
// see https://golang.org/pkg/reflect/#Value.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
https://play.golang.org/p/jL5UD7yCNq
Not sure generics are needed here. You just need a contract for your desired behavior. Doing the following is no more than what you would have to do in other languages if you wanted your own objects to behave themselves in collections, by overriding Equals() and GetHashCode() for instance.
type Identifiable interface{
GetIdentity() string
}
func IsIdentical(this Identifiable, that Identifiable) bool{
return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}
func contains(s []Identifiable, e Identifiable) bool {
for _, a := range s {
if IsIdentical(a,e) {
return true
}
}
return false
}
If it is not feasable to use a map for finding items based on a key, you can consider the goderive tool. Goderive generates a type specific implementation of a contains method, making your code both readable and efficient.
Example;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
To generate the deriveContainsFoo method:
Install goderive with go get -u github.com/awalterschulze/goderive
Run goderive ./... in your workspace folder
This method will be generated for deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive has support for quite some other useful helper methods to apply a functional programming style in go.
The go style:
func Contains(n int, match func(i int) bool) bool {
for i := 0; i < n; i++ {
if match(i) {
return true
}
}
return false
}
s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
return s[i] == "o"
})
If you have a byte slice, you can use bytes package:
package main
import "bytes"
func contains(b []byte, sub byte) bool {
return bytes.Contains(b, []byte{sub})
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
Or suffixarray package:
package main
import "index/suffixarray"
func contains(b []byte, sub byte) bool {
return suffixarray.New(b).Lookup([]byte{sub}, 1) != nil
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
If you have an int slice, you can use intsets package:
package main
import "golang.org/x/tools/container/intsets"
func main() {
var s intsets.Sparse
for n := 10; n < 20; n++ {
s.Insert(n)
}
b := s.Has(16)
println(b)
}
https://golang.org/pkg/bytes
https://golang.org/pkg/index/suffixarray
https://pkg.go.dev/golang.org/x/tools/container/intsets
I created the following Contains function using reflect package.
This function can be used for various types like int32 or struct etc.
// Contains returns true if an element is present in a slice
func Contains(list interface{}, elem interface{}) bool {
listV := reflect.ValueOf(list)
if listV.Kind() == reflect.Slice {
for i := 0; i < listV.Len(); i++ {
item := listV.Index(i).Interface()
target := reflect.ValueOf(elem).Convert(reflect.TypeOf(item)).Interface()
if ok := reflect.DeepEqual(item, target); ok {
return true
}
}
}
return false
}
Usage of contains function is below
// slice of int32
containsInt32 := Contains([]int32{1, 2, 3, 4, 5}, 3)
fmt.Println("contains int32:", containsInt32)
// slice of float64
containsFloat64 := Contains([]float64{1.1, 2.2, 3.3, 4.4, 5.5}, 4.4)
fmt.Println("contains float64:", containsFloat64)
// slice of struct
type item struct {
ID string
Name string
}
list := []item{
item{
ID: "1",
Name: "test1",
},
item{
ID: "2",
Name: "test2",
},
item{
ID: "3",
Name: "test3",
},
}
target := item{
ID: "2",
Name: "test2",
}
containsStruct := Contains(list, target)
fmt.Println("contains struct:", containsStruct)
// Output:
// contains int32: true
// contains float64: true
// contains struct: true
Please see here for more details:
https://github.com/glassonion1/xgo/blob/main/contains.go
There are several packages that can help, but this one seems promising:
https://github.com/wesovilabs/koazee
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
contains, _ := stream.Contains(7)
fmt.Printf("stream.Contains(7): %v\n", contains)
It might be considered a bit 'hacky' but depending the size and contents of the slice, you can join the slice together and do a string search.
For example you have a slice containing single word values (e.g. "yes", "no", "maybe"). These results are appended to a slice. If you want to check if this slice contains any "maybe" results, you may use
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
How suitable this is really depends on the size of the slice and length of its members. There may be performance or suitability issues for large slices or long values, but for smaller slices of finite size and simple values it is a valid one-liner to achieve the desired result.