Marc-François
Marc-François

Reputation: 4050

How do I extract a string from an interface{} variable in Go?

I'm new to the Go language.

I'm making a small web application with Go, the Gorilla toolkit, and the Mustache template engine.

Everything works great so far.

I use hoisie/mustache and gorilla/sessions, but I'm struggling with passing variables from one to the other. I have a map[string]interface{} that I pass to the template engine. When a user is logged in, I want to take the user's session data and merge it with my map[string]interface{} so that the data becomes available for rendering.

The problem is that gorilla/sessions returns a map[interface{}]interface{} so the merge cannot be done (with the skills I have in this language).

I thought about extracting the string inside the interface{} variable (reflection?). I also thought about making my session data a map[interface{}]interface{} just like what gorilla/sessions provides. But I'm new to Go and I don't know if that can be considered best practice. As a Java guy, I feel like working with variables of type Object.

I would like to know the best approach for this problem in your opinion.

Thanks in advance.

Upvotes: 3

Views: 4050

Answers (1)

elithrar
elithrar

Reputation: 24260

You'll need to perform type assertions: specifically this section of Effective Go.

str, ok := value.(string)
if ok {
    fmt.Printf("string value is: %q\n", str)
} else {
    fmt.Printf("value is not a string\n")
}

A more precise example given what you're trying to do:

if userID, ok := session.Values["userID"].(string); ok {
     // User ID is set
} else {
     // User ID is not set/wrong type; raise an error/HTTP 500/re-direct
}

type M map[string]interface{}

err := t.ExecuteTemplate(w, "user_form.tmpl", M{"current_user": userID})
if err != nil {
    // handle it
}

What you're doing is ensuring that the userID you pull out of the interface{} container is actually a string. If it's not, you handle it (if you don't, you'll program will panic as per the docs).

If it is, you pass it to your template where you can access it as {{ .current_user }}. M is a quick shortcut that I use to avoid having to type out map[string]interface{} every time I call my template rendering function.

Upvotes: 4

Related Questions