在Go中对多个返回值进行转换/类型声明的惯用方式


78

在Go中强制转换多个返回值的惯用方式是什么?

您可以单行执行吗,还是需要使用临时变量(例如我在下面的示例中所做的那样)?

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")
    }   
}

顺便说一句,casting当涉及到接口时会调用它吗?

i := interface.(int)

Answers:



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

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

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

但是您实际上想要的是使用类型开关,例如:

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在不放弃正确性的前提下也相当简洁。对于其他看到此问题的人,我认为您提到断言检查很好。就我而言,尽管我已经知道接口中存储了什么类型,所以我跳过了检查。我什至考虑过要使用anunsafe.Pointer而不是interface{},但是我猜想类型断言中没有足够的开销来证明使用不安全的指针是合理的。
阿尼斯(Anisus)2012年

1
我可能应该指出,惯用的方法是不返回interface {},而是接受interface {}作为输入参数,检查传入的类型,然后填充该类型。在encoding / json包的Unmarshal方法中很好地举例说明了这一点。这些技术不能涵盖所有相同的情况,因此可能并非总是可行,但是通常接受interface {}胜于返回interface {}。您可以使用反射包检查以确保提供的值是指针。
jorelli 2012年

14

或仅在一个情况下:

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

Go将处理if子句中的强制类型转换,并让您访问强制类型的属性。


12

template.Must是标准库在一个语句中仅返回第一个返回值的方法。可以针对您的情况类似地执行以下操作:

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

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

通过使用must您基本上说的是永远都不会有错误,如果有错误,则程序将(或者至少不应该)继续运行,而将出现恐慌。


6
恐慌不是由程序员引起的,这是很不正常的。template.Must()通常使用像这样的函数从程序包级别的声明和init()函数中的变量加载模板。这样做的想法是在运行时立即感到恐慌,并使编译器无法捕捉到的错误很明显。您不应该使用它来避免临时变量。
史蒂芬·温伯格

1
must不清楚“通过使用您基本上说应该永远不会出错”的哪一部分?除非错误仅是由程序员引起的,否则如果出现错误,则该程序实际上无法继续执行,则不应使用此选项。
Moshe Revah 2012年

1
我不同意“否则如果出现错误,该程序将无法继续执行”。在这种情况下,您仍然不应该惊慌。
斯蒂芬·温伯格

这甚至不是一个论点,因为我大都同意这一点。仅当您无法或不愿记录错误时,这才是惯用的。因此,这很少是惯用的。
Moshe Revah

1
虽然我理解了斯蒂芬的观点,但在某些情况下答案仍然有用(正如斯蒂芬也指出的那样)。感谢您的包装想法。
阿尼斯(Anisus)2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.