Élodie Petit
Élodie Petit

Reputation: 5914

Handling nil values in a map

I want to create a struct with the values in a map.

Here's a snippet:

        log := &Log{
            Facility:  parts["facility"].(int),
            Severity:  parts["severity"].(int),
            Timestamp: parts["timestamp"].(time.Time),
            Hostname:  parts["hostname"].(string),
            AppName:   parts["appName"].(string),
            Client:    parts["client"].(string),
            Priority:  parts["priority"].(int),
            Message:   parts["message"].(string),
        }

The problem is, if one of the values is nil, panic occurs. So I wanted to do something like this:

Facility:  parts["facility"] != nil ? parts["facility"].(int) : 0

But this is not a valid syntax.

Do I have to check every key separately to handle nil cases?

Upvotes: 1

Views: 3140

Answers (2)

gonutz
gonutz

Reputation: 5582

You can write a wrapper for these types if you like:

func toInt(x interface{}) int {
    if i, ok := x.(int); ok {
        return i
    }
    return 0 // Or what you would like to have as a default.
}

which can be shortened if you want to use the default value for a type:

func toInt(x interface{}) int {
    i, _ := x.(int)
    return i
}

which will make it look like this:

    log := &Log{
        Facility:  toInt(parts["facility"]),
        Severity:  toInt(parts["severity"]),
        Timestamp: toTime(parts["timestamp"]),
        Hostname:  toString(parts["hostname"]),
        AppName:   toString(parts["appName"]),
        Client:    toString(parts["client"]),
        Priority:  toInt(parts["priority"]),
        Message:   toString(parts["message"]),
    }

You could go further and write your conversion functions locally:

var parts map[string]interface{}

// ...

i := func(name string) int {
    i, _ := parts[name].(int)
    return i
}

s := func(name string) string {
    s, _ := parts[name].(string)
    return s
}

t := func(name string) time.Time {
    t, _ := parts[name].(time.Time)
    return t
}

log := &Log{
    Facility:  i("facility"),
    Severity:  i("severity"),
    Timestamp: t("timestamp"),
    Hostname:  s("hostname"),
    AppName:   s("appName"),
    Client:    s("client"),
    Priority:  i("priority"),
    Message:   s("message"),
}

Upvotes: 2

Burak Serdar
Burak Serdar

Reputation: 51542

You can do this:

 log := &Log{}
 log.Facility, _ = parts["facility"].(int)
 log.Severity, _ = parts["severity"].(int)
  ...

This will use the two-value form of type assertion, where the second value indicates if the type-assertion worked, and you then ignore that value, so the struct member is initialized with the zero-value if the map does not contain the key, or if the key is not of the required type.

Upvotes: 8

Related Questions