I have the following function:
func addCatsToMap(m map[string][]CatHouse, meowId int, treats Set, dog *Dog) { //if (complicated thing) add Cat to m }
where Set
, the type of treats
, is an interface with the following definition:
type Set interface { Add(value string) Contains(value string) (bool) Length() (int) RemoveDuplicates() }
Question:
Is it true that m
, treats
, and dog
are passed-by-reference, and meowId
has it's value copied?
I assume that:
m
is pass-by-reference because it's a mapdog
is a struct. So, I should pass the pointer to avoid copying the dataGo programming language allows you to pass a pointer to a function. To do so, simply declare the function parameter as a pointer type.
Functions can be used as function arguments, they can also be used as return values.
To be specific, Go does not support “Pass-By-Reference” semantic in any way. The reason is simple; Go does not support a reference variable as you have in other programming languages like C++.
Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French. For many Go developers, the systematic use of pointers to share structs instead of the copy itself seems the best option in terms of performance.
An interface type is simply a set of methods. Notice that the members of an interface definition do not specify whether or not the receiver type is a pointer. That is because the method set of a value type is a subset of the method set of its associated pointer type. That's a mouthful. What I mean is, if you have the following:
type Whatever struct { Name string }
and you define the following two methods:
func (w *Whatever) Foo() { ... } func (w Whatever) Bar() { ... }
Then the type Whatever
has only the method Bar()
, while the type *Whatever
has the methods Foo()
and Bar()
. That means if you have the following interface:
type Grits interface { Foo() Bar() }
Then *Whatever
implements Grits
but Whatever
does not, because Whatever
lacks the method Foo()
. When you define the input to a function as an interface type, you have no idea whether it's a pointer or a value type.
The following example illustrates a function that takes an interface type in both ways:
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) }
you could call Raname(&f, "Jorelli Fruit")
but not Rename(c, "Jorelli Bar")
, because both Fruit
and *Fruit
implement Renamable
, while *Candy
implements Renable
and Candy
does not.
http://play.golang.org/p/Fb-L8Bvuwj
Pass by reference is a language thing, nothing in Go is "pass by reference". Pass by reference means the assignment operator can change the original value when use alone. However, there are reference types such as maps and pointers which point somewhere. Using the assignment operator on them will not modify the original unless you use other operators such as the map index and the *
operator.
You are correct that your map m
is a reference type and therefore like a pointer. Any changes to the map except replacing the map will modify the original.
m["whatever"] = 2 // Modifies the original map m = anothermap // Does not modify the original map
If there was true "pass by reference", the second example would modify the original map.
Passing a pointer, as you do with dog
allows you to modify the original. If you call any pointer methods or use the *
operator, the original will change. In your example, a pointer may not have been needed. If Dog
is small, it may be easier to just pass a copy. It is up to the programmer to determine when it is a good time to use a pointer.
Set
is not passed by reference. Interfaces are not references. While it is true that internally in the 6g compiler an interface uses pointers, the interface itself does not act like one. Passing an interface, no matter of the size of the object it contains, is as cheap as passing a pointer using the 6g compiler. However, there is no way to modify the original value of an interface as you can with pointers and maps.
Although you can not modify the original interface passed, the interface can contain a pointer type. In that case it would act just like the dog pointer where the calling of certain methods can modify the original. For your particular Set
interface, I would guess it contains a pointer type based on the method names. So when you call set.Add(whatever)
, it will change the internal data of the original.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With