2

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.

3 Answers 3

5

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()
}
Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

-1

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: 

1 Comment

Perhaps I was too vague. I want String() to return a string that concatenates all of the key and values to a single string and then returns that strings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.