How could I write a function to print a map object in Go (Golang)? Right now I have this, but it doesn't compile. It returns cannot convert value (type interface {}) to type reflect.Kind: need type assertion.
package main
type MyDictionary map[string]interface{}
func (d MyDictionary) String() string {
var stringBuffer bytes.Buffer
for key, value := range d {
stringBuffer.WriteString(key)
stringBuffer.WriteString(": ")
valueType := reflect.Kind(value)
switch valueType {
case reflect.String:
log.Println("string") // just to check if this block gets executed
// Add to stringBuffer
case reflect.Float64:
log.Println("float64") // just to check if this block gets executed
// Add to stringBuffer
default:
log.Println("Error: type was", valueType)
}
}
return stringBuffer.String()
}
func main() {
var dict MyDictionary = make(MyDictionary)
dict["hello"] = "world"
dict["floating"] = 10.0
dict["whole"] = 12
fmt.Println(dict)
}
I want String() to return a string like hello: world\nfloating: 10.0\nwhole: 12\n. That I can then pass to fmt.Println() to print this. In Java, I would use StringBuilder for this.
hello: world
floating: 10.0
whole: 12
I also tried switching on value.(type) with case string: and case float64, but then I didn't know how to write those values to stringBuffer.
Here's an idiomatic solution.
func (d MyDictionary) String() string {
var buf bytes.Buffer
for k, v := range d {
buf.WriteString(k + ": ")
// v is an interface{} here
switch v := v.(type) {
// The inner v is typed. It shadows the outer interface{} v. That's
// the idiomatic part.
case string:
buf.WriteString(v + "\n") // v is a string
case int:
buf.WriteString(fmt.Sprintln(v)) // v is an int
case float64:
buf.WriteString(fmt.Sprintln(v)) // v is a float64
}
}
return buf.String()
}
You can potentially simplify it to this (playground):
func (d MyDictionary) String() string {
var result string
for key, value := range d {
result += fmt.Sprintf("%s: %v\n", key, value)
}
return result
}
Which prints:
hello: world
floating: 10
whole: 12
Obviously, the "whole" floating point has the decimals removed (if you set it to 10.5 it will print properly). If that's required, then you'll want to switch on the float and specify precision as well (playground):
func (d MyDictionary) String() string {
var result string
for key, value := range d {
switch value.(type) {
case float64:
result += fmt.Sprintf("%s: %.2f\n", key, value)
default:
result += fmt.Sprintf("%s: %v\n", key, value)
}
}
return result
}
Which prints:
floating: 10.00
whole: 12
hello: world
You need to get the type of the interface and then switch on the kind of the type.
valueType := reflect.TypeOf(value).Kind()
Working Example: http://play.golang.org/p/a-7SePUzZ-
package main
import (
"bytes"
"fmt"
"log"
"reflect"
)
type MyDictionary map[string]interface{}
func (d MyDictionary) String() string {
var stringBuffer bytes.Buffer
for key, value := range d {
stringBuffer.WriteString(key)
stringBuffer.WriteString(": ")
valueType := reflect.TypeOf(value).Kind()
switch valueType {
case reflect.String:
log.Println("string")
default:
log.Println("Type was:", valueType)
}
}
return stringBuffer.String()
}
func main() {
var dict MyDictionary = make(MyDictionary)
dict["hello"] = "world"
dict["floating"] = 10.0
dict["whole"] = 12
fmt.Println(dict)
}
Output
2009/11/10 23:00:00 string
2009/11/10 23:00:00 Type was: float64
2009/11/10 23:00:00 Type was: int
hello: floating: whole:
Related
package main
import "fmt"
type A struct {
a int32
B *B
}
type B struct {
b int32
}
func main() {
a := &A{
a: 1,
B: &B{
b: 2,
},
}
fmt.Printf("v ==== %+v \n", a)
}
//ret: v ==== &{a:1 B:0xc42000e204}
//??? how to print B's content but not pointer
Basically, you have to do it yourself. There are two ways to do this. Either just print the thing how you want, or implement the Stringer interface for the struct by adding a func String() string, which gets called when you use the format %v. You could also reference each value in the format which is a struct.
Implementing the Stringer interface is the surest way to always get what you want. And you only have to do it once per struct, instead of per format string when you print.
https://play.golang.org/p/PKLcPFCqOe
package main
import "fmt"
type A struct {
a int32
B *B
}
type B struct{ b int32 }
func (aa *A) String() string {
return fmt.Sprintf("A{a:%d, B:%v}",aa.a,aa.B)
}
func (bb *B) String() string {
return fmt.Sprintf("B{b:%d}",bb.b)
}
func main() {
a := &A{a: 1, B: &B{b: 2}}
// using the Stringer interface
fmt.Printf("v ==== %v \n", a)
// or just print it yourself however you want.
fmt.Printf("v ==== A{a:%d, B:B{b:%d}}\n", a.a, a.B.b)
// or just reference the values in the struct that are structs themselves
// but this can get really deep
fmt.Printf("v ==== A{a:%d, B:%v}", a.a, a.B)
}
When you get into larger structs, it becomes a pain to write a bunch of custom String functions. Goconvey currently uses the following project to show diffs and expected/actual output on structs of any size: https://github.com/luci/go-render/blob/master/render/render.go#L51. It includes displaying pointer values.
If you need the output to be re-usable as code (like fmt.Printf("%#v", a) but include pointer values), I have a forked version of the above project which will render full nested pointers as re-usable code:
package main
import (
"fmt"
"github.com/gdexlab/go-render/render"
)
type A struct {
a int32
B *B
}
type B struct {
b int32
}
func main() {
a := &A{
a: 1,
B: &B{
b: 2,
},
}
output := render.AsCode(a)
fmt.Println(output)
}
// outputs: "&A{a:1, B:&B{b:2}}" compared to initial version of "&{a:1 B:0xc42000e204}"
Go Playground Example:
https://play.golang.org/p/tcfJYb0NnVf
Another simple solution is to print the struct using marshaling. This works only for exported (public) variables by capitalizing the first char inside the struct.
package main
import (
"fmt"
"gopkg.in/yaml.v2"
"encoding/json"
)
type A struct {
Aa int32
B *B
}
type B struct {
Bb int32
}
func main() {
a := &A{
Aa: 1,
B: &B{
Bb: 2,
},
}
aJSON, _ := json.Marshal(a)
fmt.Printf("JSON Print - \n%s\n", string(aJSON))
aYAML, _ := yaml.Marshal(a)
fmt.Printf("YAML Print - \n%s\n", string(aYAML))
}
Output :-
JSON Print -
{"Aa":1,"B":{"Bb":2}}
YAML Print -
aa: 1
b:
bb: 2
If you are printing the struct multiple times then implement Stringer interface as follows :-
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type A struct {
Aa int32
B *B
}
func (a A) String() string {
bytes, _ := yaml.Marshal(a)
return string(bytes)
}
type B struct {
Bb int32
}
func main() {
a := &A{
Aa: 1,
B: &B{
Bb: 2,
},
}
fmt.Printf("YAML Print - \n%+v\n", a)
}
Output -
YAML Print -
aa: 1
b:
bb: 2
Use fmt and reflect.
package main
import (
"fmt"
"reflect"
)
type A struct {
a int32
B *B
}
type B struct {
b int32
}
func main() {
a := &A{
a: 1,
B: &B{
b: 2,
},
}
fmt.Printf("%s\n", GetGoString(a)) // output: &A{a: 1, B: &B{b: 2}}
}
func GetGoString(v interface{}) string {
return getGoString(reflect.ValueOf(v))
}
func getGoString(v reflect.Value) string {
switch v.Kind() {
case reflect.Invalid:
return "nil"
case reflect.Struct:
t := v.Type()
out := getTypeString(t) + "{"
for i := 0; i < v.NumField(); i++ {
if i > 0 {
out += ", "
}
fieldValue := v.Field(i)
field := t.Field(i)
out += fmt.Sprintf("%s: %s", field.Name, getGoString(fieldValue))
}
out += "}"
return out
case reflect.Interface, reflect.Ptr:
if v.IsZero() {
return fmt.Sprintf("(%s)(nil)", getTypeString(v.Type()))
}
return "&" + getGoString(v.Elem())
case reflect.Slice:
out := getTypeString(v.Type())
if v.IsZero() {
out += "(nil)"
} else {
out += "{"
for i := 0; i < v.Len(); i++ {
if i > 0 {
out += ", "
}
out += getGoString(v.Index(i))
}
out += "}"
}
return out
default:
return fmt.Sprintf("%#v", v)
}
}
func getTypeString(t reflect.Type) string {
if t.PkgPath() == "main" {
return t.Name()
}
return t.String()
}
Implement Stringer interface to custom type
no external packages
no need to wrap types in other types
example:
package main
import "fmt"
type A struct {
B *B `json:"b"`
}
type B int
func (b *B) String() string {
if b == nil {
return "nil"
}
return fmt.Sprintf("%d", *b)
}
func main() {
var a A
fmt.Printf("a: %+v\n", a)
a.B = B(3)
fmt.Printf("a: %+v\n", a)
}
output:
a: {B:nil}
a: {B:3}
I would like to make this function more generic (with a "for")
func (e example) ScanRow(rows *sql.Rows) (example, error) {
val := reflect.ValueOf(e)
test := make([]interface{}, val.Type().NumField())
test[0] = &e.Id
test[1] = &e.CreatedAt
test[2] = &e.Text
test[3] = &e.AuthorId
test[4] = &e.CategoryId
if err := rows.Scan(test[0], test[1], test[2], test[3], test[4]); err != nil {
return e, err
}
return e, nil
}
Here is the struct example:
type example struct {
Id int `json:"id"`
CreatedAt string `json:"created_at"`
Text string `json:"text"`
AuthorId int `json:"author_id"`
CategoryId int `json:"category_id"`
}
Do you think it's possible ? I am trying to find a way to do that but i am lost...
I am trying to create a function that could accept following
*struct
[]*struct
map[string]*struct
Here struct could be any struct not just a specific one.
Converting interface to *struct or []*struct is working fine.
But giving error for map.
After reflect it shows it is map[] but giving error when try to iterate over range.
Here is code
package main
import (
"fmt"
"reflect"
)
type Book struct {
ID int
Title string
Year int
}
func process(in interface{}, isSlice bool, isMap bool) {
v := reflect.ValueOf(in)
if isSlice {
for i := 0; i < v.Len(); i++ {
strct := v.Index(i).Interface()
//... proccess struct
}
return
}
if isMap {
fmt.Printf("Type: %v\n", v) // map[]
for _, s := range v { // Error: cannot range over v (type reflect.Value)
fmt.Printf("Value: %v\n", s.Interface())
}
}
}
func main() {
b := Book{}
b.Title = "Learn Go Language"
b.Year = 2014
m := make(map[string]*Book)
m["1"] = &b
process(m, false, true)
}
Is there any way to convert interface{} to map and iterate or get it's elements.
If the map value can be any type, then use reflect to iterate through the map:
if v.Kind() == reflect.Map {
for _, key := range v.MapKeys() {
strct := v.MapIndex(key)
fmt.Println(key.Interface(), strct.Interface())
}
}
playground example
If there's a small and known set of struct types, then a type switch can be used:
func process(in interface{}) {
switch v := in.(type) {
case map[string]*Book:
for s, b := range v {
// b has type *Book
fmt.Printf("%s: book=%v\n" s, b)
}
case map[string]*Author:
for s, a := range v {
// a has type *Author
fmt.Printf("%s: author=%v\n" s, a)
}
case []*Book:
for i, b := range v {
fmt.Printf("%d: book=%v\n" i, b)
}
case []*Author:
for i, a := range v {
fmt.Printf("%d: author=%v\n" i, a)
}
case *Book:
fmt.Ptintf("book=%v\n", v)
case *Author:
fmt.Printf("author=%v\n", v)
default:
// handle unknown type
}
}
You don't need reflect here. Try:
v, ok := in.(map[string]*Book)
if !ok {
// Can't assert, handle error.
}
for _, s := range v {
fmt.Printf("Value: %v\n", s)
}
Same goes for the rest of your function. It looks like you're using reflection when you would be better served by a type switch.
Alternatively, if you insist on using reflection here (which doesn't make a lot of sense) you can also use Value.MapKeys with the result from your ValueOf (see the answer https://stackoverflow.com/a/38186057/714501)
This may help:
b := []byte(`{"keyw":"value"}`)
var f interface{}
json.Unmarshal(b, &f)
myMap := f.(map[string]interface{})
fmt.Println(myMap)
Another way to convert an interface{} into a map with the package reflect is with MapRange.
I quote:
MapRange returns a range iterator for a map. It panics if v's Kind is
not Map.
Call Next to advance the iterator, and Key/Value to access each entry.
Next returns false when the iterator is exhausted. MapRange follows
the same iteration semantics as a range statement.
Example:
iter := reflect.ValueOf(m).MapRange()
for iter.Next() {
key := iter.Key().Interface()
value := iter.Value().Interface()
...
}
I can create a "static" map via
type m map[int]map[int]map[int]bool
but the length of "keys" will be dynamic:
|---unknown len--|
m[1][2][3][4][2][0] = true
or
|---unk len--|
m[1][2][3][4] = true
How I can create this map in Go? Or any way exists?
Added: Hierarchical is IMPORTANT
Thanks in advance!
The map type:
A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type.
A map type must have a specific value type and a specific key type. What you want does not qualify for this: you want a map where the value is sometimes another map (of the same type), and sometimes it's a bool.
Your options:
1. With a wrapper value type
The idea here is to not use just a simple (bool) value type, but a wrapper which holds both of your potential values: both a map and the simple value (bool):
type Value struct {
Children MapType
V bool
}
type MapType map[int]*Value
var m MapType
This is basically what user3591723 suggested, so I won't detail it further.
2. With a tree
This is a variant of #1, but this way we clearly communicate it's a tree.
The cleanest way to implement your hierarchical structure would be to use a tree, where a node could look like this:
type KeyType int
type ValueType string
type Node struct {
Children map[KeyType]*Node
Value ValueType
}
This has the advantage that you may choose the value type (which is bool in your case, but you can change it to whatever type - I used string for presentation).
For easily build / manage your tree, we can add some methods to our Node type:
func (n *Node) Add(key KeyType, v ValueType) {
if n.Children == nil {
n.Children = map[KeyType]*Node{}
}
n.Children[key] = &Node{Value: v}
}
func (n *Node) Get(keys ...KeyType) *Node {
for _, key := range keys {
n = n.Children[key]
}
return n
}
func (n *Node) Set(v ValueType, keys ...KeyType) {
n = n.Get(keys...)
n.Value = v
}
And using it: 1. build a tree, 2. query some values, 3. change a value:
root := &Node{Value: "root"}
root.Add(0, "first")
root.Get(0).Add(9, "second")
root.Get(0, 9).Add(3, "third")
root.Get(0).Add(4, "fourth")
fmt.Println(root)
fmt.Println(root.Get(0, 9, 3))
fmt.Println(root.Get(0, 4))
root.Set("fourthMod", 0, 4)
fmt.Println(root.Get(0, 4))
Output (try it on the Go Playground):
&{map[0:0x104382f0] root}
&{map[] third}
&{map[] fourth}
&{map[] fourthMod}
3. With a recursive type definition
It may be surprising but it is possible to define a map type in Go which has unlimited or dynamic "depth", using a recursive definition:
type X map[int]X
It is what it says: it's a map with int keys, and values of the same type as the map itself.
The big downside of this recursive type is that it can't store any "useful" data in the value type. It can only store the "fact" whether a value is present which is identical to a bool-like information (bool type: true or false), which may be enough in rare cases, but not in most.
Let's see an example building a "tree":
var x X
x = map[int]X{}
x[0] = map[int]X{}
x[0][9] = map[int]X{}
x[0][9][3] = map[int]X{}
x[0][4] = map[int]X{}
fmt.Println(x)
Output:
map[0:map[9:map[3:map[]] 4:map[]]]
If we want to test if there is a "value" based on a series of keys, we have 2 options: either use the special v, ok := m[i] indexing (which reports if a value for the specified key exists), or test if the value is not nil, e.g. m[i] != nil.
Let's see some examples testing the above built map:
var ok bool
_, ok = x[0][9][3]
fmt.Println("x[0][9][3] exists:", ok, "; alternative way:", x[0][9][3] != nil)
_, ok = x[0][9][4]
fmt.Println("x[0][9][4] exists:", ok, "; alternative way:", x[0][9][4] != nil)
_, ok = x[0][4]
fmt.Println("x[0][4] exists:", ok, "; alternative way:", x[0][4] != nil)
_, ok = x[0][4][9][9][9]
fmt.Println("x[0][4][9][9][9] exists:", ok, "; alternative way:", x[0][4][9][9][9] != nil)
Output:
x[0][9][3] exists: true ; alternative way: true
x[0][9][4] exists: false ; alternative way: false
x[0][4] exists: true ; alternative way: true
x[0][4][9][9][9] exists: false ; alternative way: false
Try these on the Go Playground.
Note: Even though x[0][4] is the last "leaf", indexing further like x[0][4][9][9][9] will not cause a panic as a nil map can be indexed and yields the zero value of the value type (which is nil in case the value type is a map type).
Ok I had some fun playing with this a bit. Here is a much better implementation than what I did before:
type mymap map[int]*myentry
type myentry struct {
m mymap
b bool
}
func (mm mymap) get(idx ...int) *myentry {
if len(idx) == 0 {
return nil
}
entry, ok := mm[idx[0]]
if !ok {
return nil
} else if len(idx) == 1 {
return entry
}
for i := 1; i < len(idx); i++ {
if entry == nil || entry.m == nil {
return nil
}
entry = entry.m[idx[i]]
}
return entry
}
func (mm mymap) setbool(v bool, idx ...int) {
if len(idx) == 0 {
return
}
if mm[idx[0]] == nil {
mm[idx[0]] = &myentry{m: make(mymap), b: false}
} else if mm[idx[0]].m == nil {
mm[idx[0]].m = make(mymap)
}
if len(idx) == 1 {
mm[idx[0]].b = v
return
}
entry := mm[idx[0]]
for i := 1; i < len(idx); i++ {
if entry.m == nil {
entry.m = make(mymap)
entry.m[idx[i]] = &myentry{m: make(mymap), b: false}
} else if entry.m[idx[i]] == nil {
entry.m[idx[i]] = &myentry{m: make(mymap), b: false}
}
entry = entry.m[idx[i]]
}
entry.b = v
}
func (m mymap) getbool(idx ...int) bool {
if val := m.get(idx...); val != nil {
return val.b
}
return false
}
func (m mymap) getmap(idx ...int) mymap {
if val := m.get(idx...); val != nil {
return val.m
}
return nil
}
Playground link
Something like that ought to get you started
If you don't need the hierarchical map structure and just want to use keys with variable length one approach could be to simply use strings as keys and one single map.
m := make(map[string]bool)
k := fmt.Sprintf("%v_%v_%v", 1, 2, 3)
m[k] = true
fmt.Println(m[k])
You cannot do this as this sort of type is not representable in Go's type system.
You will have to redesign.
E.g. a type arbitrarilyKeyedMapwith a method lookup(vals ...int) bool.
Probably you'll need methods for setting and deletion too.
I am trying to implement a method to get a value from a arbitrary struct-field as a string given by the struct and the fieldname as a string.
With reflect it is always panicing.
panic: reflect: call of reflect.Value.FieldByName on interface Value
goroutine 16 [running]
// attempt to implement GetStringValueByFieldName()
package main
import "fmt"
import "reflect"
import "strconv"
func main() {
a:=Order{A:"asdf", B:123}
fmt.Println(a)
fmt.Println(Test1(a, "A"))
fmt.Println(Test1(a, "B"))
}
type Order struct {
A string
B int64
}
func Test1 (n interface{}, field_name string) string {
var x string
s := reflect.ValueOf(&n).Elem()
x, ok := s.FieldByName(field_name).Interface().(string)
if ok {
fmt.Println(ok)
}
return x
}
func GetStringValueByFieldName(n interface{}, field_name string) string {
ps := reflect.ValueOf(&n)
// struct
s := ps.Elem()
if s.Kind() == reflect.Struct {
f := s.FieldByName(field_name)
if f.IsValid() {
if f.CanSet() {
if f.Kind() == reflect.Int {
return strconv.FormatInt(f.Int(),10)
}
if f.Kind() == reflect.String {
return f.String()
}
}
}
}
return ""
}
Here's how to get a string field by name:
package main
import (
"fmt"
"reflect"
)
func main() {
a := Order{A: "asdf", B: 123}
fmt.Println(a)
fmt.Println(GetStringValueByFieldName(a, "A"))
fmt.Println(GetStringValueByFieldName(&a, "A"))
fmt.Println(GetStringValueByFieldName(a, "B"))
fmt.Println(GetStringValueByFieldName(0, "B"))
fmt.Println(GetStringValueByFieldName(a, "C"))
}
type Order struct {
A string
B int64
}
func GetStringValueByFieldName(n interface{}, field_name string) (string, bool) {
s := reflect.ValueOf(n)
if s.Kind() == reflect.Ptr {
s = s.Elem()
}
if s.Kind() != reflect.Struct {
return "", false
}
f := s.FieldByName(field_name)
if !f.IsValid() {
return "", false
}
switch f.Kind() {
case reflect.String:
return f.Interface().(string), true
case reflect.Int:
return strconv.FormatInt(f.Int(), 10), true
// add cases for more kinds as needed.
default:
return "", false
// or use fmt.Sprint(f.Interface())
}
}
playground