golang pointers on pointers as function parameters

前端 未结 3 727
夕颜
夕颜 2021-01-30 05:38

I have the following function:

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

//if (complicated thing) add Cat to m

}
<         


        
相关标签:
3条回答
  • 2021-01-30 06:19

    Calls, The Go Programming Language Specification

    In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the calling function when the function returns.

    When are function parameters passed by value? FAQ - The Go Programming Language.

    As in all languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter. For instance, passing an int value to a function makes a copy of the int, and passing a pointer value makes a copy of the pointer, but not the data it points to. (See the next section for a discussion of how this affects method receivers.)

    Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to. Copying an interface value makes a copy of the thing stored in the interface value. If the interface value holds a struct, copying the interface value makes a copy of the struct. If the interface value holds a pointer, copying the interface value makes a copy of the pointer, but again not the data it points to.

    0 讨论(0)
  • 2021-01-30 06:20

    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.

    0 讨论(0)
  • 2021-01-30 06:26

    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

    0 讨论(0)
提交回复
热议问题