Idiomatic way to do conversion/type assertion on m

2020-05-13 08:19发布

问题:

What is the idiomatic way to cast multiple return values in Go?

Can you do it in a single line, or do you need to use temporary variables such as I've done in my example below?

package main

import "fmt"

func oneRet() interface{} {
    return "Hello"
}

func twoRet() (interface{}, error) {
    return "Hejsan", nil
}

func main() {
    // With one return value, you can simply do this
    str1 := oneRet().(string)
    fmt.Println("String 1: " + str1)

    // It is not as easy with two return values
    //str2, err := twoRet().(string) // Not possible
    // Do I really have to use a temp variable instead?
    temp, err := twoRet()
    str2 := temp.(string)
    fmt.Println("String 2: " + str2 )


    if err != nil {
        panic("unreachable")
    }   
}

By the way, is it called casting when it comes to interfaces?

i := interface.(int)

回答1:

You can't do it in a single line. Your temporary variable approach is the way to go.

By the way, is it called casting when it comes to interfaces?

It is actually called a type assertion. A type cast conversion is different:

var a int
var b int64

a = 5
b = int64(a)


回答2:

func silly() (interface{}, error) {
    return "silly", nil
}

v, err := silly()
if err != nil {
    // handle error
}

s, ok := v.(string)
if !ok {
    // the assertion failed.
}

but more likely what you actually want is to use a type switch, like-a-this:

switch t := v.(type) {
case string:
    // t is a string
case int :
    // t is an int
default:
    // t is some other type that we didn't name.
}

Go is really more about correctness than it is about terseness.



回答3:

template.Must is the standard library's approach for returning only the first return value in one statement. Could be done similarly for your case:

func must(v interface{}, err error) interface{} {
    if err != nil {
        panic(err)
    }
    return v
}

// Usage:
str2 := must(twoRet()).(string)

By using must you basically say that there should never be an error, and if there is, then the program can't (or at least shouldn't) keep operating, and will panic instead.



回答4:

Or just in a single if:

if v, ok := value.(migrater); ok {
    v.migrate()
}

Go will take care of the cast inside the if clause and let you access the properties of the casted type.