web-dev-qa-db-fra.com

Manière idiomatique de faire une conversion / une assertion de type sur plusieurs valeurs de retour dans Go

Quelle est la manière idiomatique de convertir plusieurs valeurs de retour dans Go?

Pouvez-vous le faire en une seule ligne ou devez-vous utiliser des variables temporaires telles que celles décrites dans l'exemple ci-dessous?

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

À propos, est-ce que cela s'appelle casting en ce qui concerne les interfaces?

i := interface.(int)
68
ANisus

Vous ne pouvez pas le faire en une seule ligne. Votre approche variable temporaire est la voie à suivre.

À propos, est-ce que ça s'appelle casting quand il s'agit d'interfaces?

On l'appelle en fait type assertion . Un type jeter la conversion est différente:

var a int
var b int64

a = 5
b = int64(a)
64
jimt
func silly() (interface{}, error) {
    return "silly", nil
}

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

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

mais il est plus probable que vous souhaitiez réellement utiliser un commutateur de type, comme-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 est vraiment plus une question de correction que de concision.

28
jorelli

template.Must est l'approche de la bibliothèque standard pour renvoyer uniquement la première valeur renvoyée dans une instruction. Pourrait être fait de la même manière pour votre cas:

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

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

En utilisant must, vous dites en gros qu'il ne devrait jamais y avoir d'erreur, et s'il y en a un, le programme ne peut pas (ou du moins ne devrait pas) continuer à fonctionner et panique à la place.

13
Moshe Revah

Ou simplement en un seul si:

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

Go se chargera de la conversion dans la clause if et vous permettra d'accéder aux propriétés du type converti.

10
Tarion