123 votes

Pourquoi puis-je taper des fonctions alias et les utiliser sans les caster?

En Go, si vous définissez un nouveau type par exemple :

type MyInt int

Vous ne pouvez alors pas passer un MyInt à une fonction attendue en tant qu'int, ou vice versa :

func test(i MyInt) {
    //faire quelque chose avec i
}

func main() {
    anInt := 0
    test(anInt) //ne fonctionne pas, int n'est pas de type MyInt
}

D'accord. Mais pourquoi est-ce que la même chose ne s'applique pas aux fonctions? par exemple :

type MyFunc func(i int)
func (m MyFunc) Run(i int) {
    m(i)
}

func run(f MyFunc, i int) {
    f.Run(i)
}

func main() {
    var newfunc func(int) //déclaration explicite
    newfunc = func(i int) {
        fmt.Println(i)
    }
    run(newfunc, 10) //fonctionne très bien, même si les types semblent différer
}

Je ne me plains pas car cela m'évite de devoir caster explicitement newfunc en type MyFunc, comme je devrais le faire dans le premier exemple; cela semble simplement incohérent. Je suis sûr qu'il y a une bonne raison à cela; quelqu'un pourrait-il m'éclairer?

La raison pour laquelle je demande est principalement parce que j'aimerais raccourcir certains de mes types de fonctions plutôt longs de cette manière, mais je veux être sûr que c'est prévu et acceptable de le faire :)

175voto

lytnus Points 990

Il s'avère que c'est un malentendu que j'avais sur la façon dont Go traitait les types, qui peut être résolu en lisant la partie pertinente de la spécification :

http://golang.org/ref/spec#Type_identity

La distinction pertinente dont j'étais ignorante était celle des types nommés et non nommés.

Les types nommés sont des types avec un nom, tels que int, int64, float, string, bool. De plus, tout type que vous créez en utilisant 'type' est un type nommé.

Les types non nommés sont ceux comme []string, map[string]string, [4]int. Ils n'ont pas de nom, simplement une description correspondant à leur fonctionnement.

Si vous comparez deux types nommés, les noms doivent correspondre pour qu'ils soient interchangeables. Si vous comparez un type nommé et un type non nommé, alors tant que la représentation sous-jacente correspond, vous êtes bons pour continuer !

par exemple, étant donné les types suivants :

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)

ceci est invalide :

var i int = 2
var i2 MyInt = 4
i = i2 // les deux sont nommés (int et MyInt) et les noms ne correspondent pas, donc invalide

ceci est correct :

is := make([]int)
m := make(map[int]int)
f := func(i int){}

//OK: comparant un type nommé et un type non nommé, et la représentation sous-jacente
//est la même :
func doSlice(input MySlice){...}
doSlice(is)

func doMap(input MyMap){...}
doMap(m)

func doFunc(input MyFunc){...}
doFunc(f)

Je suis un peu déçu de ne pas l'avoir su plus tôt, j'espère que cela éclaircit un peu la question des types pour quelqu'un d'autre ! Et signifie beaucoup moins de conversion que je ne le pensais au départ :)

20voto

Mingyu Points 3874

La question et la réponse sont toutes deux assez éclairantes. Cependant, j'aimerais souligner une distinction qui n'est pas claire dans la réponse de lytnus.

  • Type Nomme est différent du Type Non Nomme.

  • La variable de Type Nomme est assignable à la variable de Type Non Nomme, vice versa.

  • Les variables de différents Types Nommes ne sont pas assignables entre eux.

http://play.golang.org/p/uaYHEnofT9

import (
    "fmt"
    "reflect"
)

type T1 []string
type T2 []string

func main() {
    foo0 := []string{}
    foo1 := T1{}
    foo2 := T2{}
    fmt.Println(reflect.TypeOf(foo0))
    fmt.Println(reflect.TypeOf(foo1))
    fmt.Println(reflect.TypeOf(foo2))

    // Output:
    // []string
    // main.T1
    // main.T2

    // foo0 peut être attribué à foo1, vice versa
    foo1 = foo0
    foo0 = foo1

    // foo2 ne peut pas être attribué à foo1
    // prog.go:28: cannot use foo2 (type T2) as type T1 in assignment
    // foo1 = foo2
}

1voto

Snehil Singh Points 21

Si le type sous-jacent ultime (comme un type peut-être un cas) est un type primitif, GO ne permettra pas l'assignation directe d'une variable d'un type à un autre type directement et vice versa. Cependant, la valeur peut être convertie en le type de destination et utilisée.

package main
import (
    "fmt"
)

type T int

type U T

type V U

type UU U

func main() {

    var s int 
    var t T   
    var u U
    var uu UU

    s = 9
    t = 10
    u = 11
    uu = 111

    fmt.Println(s)
    fmt.Println(t)
    fmt.Println(u)
    fmt.Println(uu)

    fmt.Println("========")

    //s = t
    //u = s
    //v = s

    u = (U)(uu)

    //fmt.Println(s)
    //fmt.Println(u)
    fmt.Println(u)

}

0voto

mvndaai Points 454

Comme les autres l'ont dit anInt := 0 choisit un type pour 0 plutôt qu'un simple nombre. La seule façon que je connaisse de le conserver sans type est d'utiliser const. Si vous utilisez const au lieu de := alors cela peut fonctionner.

func main() {
    const anInt = 0
    test(anInt)
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X