pointeurs de golang sur les pointeurs comme paramètres de fonction

j'ai la fonction

func addCatsToMap(m map[string][]CatHouse, meowId int, treats Set, dog *Dog) {

//if (complicated thing) add Cat to m

}

est-il vrai que m, treats, et dog sont passés par référence, et meowId a sa valeur copiée.

Puisque m est la carte, de son passé par référence.

Chien est un struct. Donc, je devrais passer le pointeur pour éviter de copier les données.

est une interface, telle que définie ici:

type Set interface {
  Add(value string)
  Contains(value string) (bool)
  Length() (int)
  RemoveDuplicates()
}

Est Défini par la valeur?

19
demandé sur Nick Siderakis 2012-06-21 05:59:32

3 réponses

un type d'interface est simplement un ensemble de méthodes. Notez que les membres d'une définition d'interface ne précisent pas si le type de récepteur est un pointeur ou non. C'est parce que la méthode de la valeur type est un sous-ensemble de la méthode de l'ensemble de ses associés type de pointeur. C'est une bouchée. Ce que je veux dire, c'est, si vous avez ce qui suit:

type Whatever struct {
    Name string
}

et vous définissez les deux méthodes suivantes:

func (w *Whatever) Foo() {
    ...
}

func (w Whatever) Bar() {
    ...
}

alors tapez Whatever n'a que le méthode Bar(), alors que le type *Whatever a les méthodes Foo() et Bar(). Cela signifie que si vous avez l'interface suivante:

type Grits interface {
    Foo()
    Bar()
}

*Whatever implémente Grits mais Whatever n'est pas, parce que Whatever n'a pas la méthode Foo(). Lorsque vous définissez l'entrée d'une fonction d'un type d'interface, vous n'avez aucune idée de si c'est un pointeur ou un type de valeur.

L'exemple suivant illustre une fonction qui prend un type d'interface dans les deux façons:

package main

import "fmt"

type Fruit struct {
    Name string
}

func (f Fruit) Rename(name string) {
    f.Name = name
}

type Candy struct {
    Name string
}

func (c *Candy) Rename(name string) {
    c.Name = name
}

type Renamable interface {
    Rename(string)
}

func Rename(v Renamable, name string) {
    v.Rename(name)
    // at this point, we don't know if v is a pointer type or not.
}

func main() {
    c := Candy{Name: "Snickers"}
    f := Fruit{Name: "Apple"}
    fmt.Println(f)
    fmt.Println(c)
    Rename(f, "Zemo Fruit")
    Rename(&c, "Zemo Bar")
    fmt.Println(f)
    fmt.Println(c)
}

on pourrait appeler Raname(&f, "Jorelli Fruit") mais pas Rename(c, "Jorelli Bar"), parce que les deux Fruit et *Fruit œuvre Renamable tandis que *Candy implémente Renable et Candy n'est pas.

http://play.golang.org/p/Fb-L8Bvuwj

38
répondu jorelli 2012-06-21 04:06:16

passer par référence est une chose de langue, rien dans Go n'est"passer par référence". Passer par référence signifie que l'opérateur d'affectation peut changer la valeur originale lorsqu'il est utilisé seul. Cependant, il existe des types de référence tels que des cartes et des pointeurs qui pointent quelque part. L'utilisation de l'opérateur de tâche sur eux ne modifiera pas l'original à moins que vous n'utilisiez d'autres opérateurs tels que l'index de carte et le * opérateur.

Vous avez raison que votre carte m est un type de référence et par conséquent, comme un pointeur. Tout changement à la carte, sauf le remplacement de la carte, modifiera l'original.

m["whatever"] = 2           // Modifies the original map
m = anothermap              // Does not modify the original map

S'il y avait true "pass by reference", le second exemple modifierait la carte originale.

passer un pointeur, comme vous le faites avec dog permet de modifier l'original. Si vous appelez n'importe quelles méthodes de pointeur ou utilisez le * opérateur, l'original va changer. Dans votre exemple, un pointeur peut ne pas avoir été nécessaire. Si Dog est petit, il peut être plus facile pour il suffit de passer une copie. C'est au programmeur pour déterminer quand il est un bon moment pour utiliser un pointeur.

Set n'est pas passé par référence. les Interfaces ne sont pas des références. bien qu'il soit vrai que dans le compilateur 6g une interface utilise des pointeurs, l'interface elle-même n'agit pas comme telle. Passer une interface, quelle que soit la taille de l'objet qu'elle contient, est aussi bon marché que passer un pointeur en utilisant le compilateur 6g. Cependant, il n'existe aucun moyen de modifier le valeur originale d'une interface comme vous pouvez avec des pointeurs et des cartes.

bien que vous ne puissiez pas modifier l'interface originale passée, l'interface peut contenir un type de pointeur. Dans ce cas, il agirait tout comme le pointeur de chien où l'appel de certaines méthodes peut modifier l'original. Pour votre Set interface, je suppose qu'il contient un type de pointeur basé sur les noms de méthode. Ainsi, lorsque vous appelez set.Add(whatever), il va modifier les données internes de l'original.

6
répondu Stephen Weinberg 2012-06-21 03:47:25

Appels, L'Aller Langage De Programmation Spécification

dans un appel de fonction, la valeur et les arguments de la fonction sont évalués en l'ordre habituel. Après ils sont évalués, les paramètres de l'appel sont passés par valeur à la fonction et la fonction appelée commence exécution. Le retour des paramètres de la fonction sont passés par valeur retour à la fonction d'appel lorsque la fonction retourne.

Quand sont fonction paramètres passés en valeur? FAQ-Le Go Langage De Programmation.

Comme dans toutes les langues de la famille C, tout à Go est passé par la valeur. C'est une fonction obtient toujours un copie de la chose transmise, comme s'il y avait une cession déclaration de l'affectation de la valeur du paramètre. Par exemple, en passant une valeur int à une fonction fait une copie de l'int, et la valeur du pointeur fait une copie du pointeur, mais pas les données qu'il pointe de. (Voir la section suivante pour une discussion sur la façon dont cela affecte la méthode récepteur.)

les valeurs Map et slice se comportent comme des pointeurs: ce sont des descripteurs qui contient des pointeurs vers la carte ou les données slice sous-jacentes. La copie d'une carte ou d' la valeur slice ne copie pas les données qu'elle pointe. Copier une interface la valeur fait une copie de la chose stockée dans la valeur de l'interface. Si l' la valeur de l'interface contient une structure, la copie de la valeur de l'interface copie de la struct. Si la valeur de l'interface est un pointeur, la copie l'interface de la valeur rend une copie du pointeur, mais encore une fois pas le données de points.

3
répondu peterSO 2012-06-21 17:28:00