douwo6738 2016-05-25 19:57
浏览 64
已采纳

在结构上调用函数的正确的go习惯用法是什么?

I am new to go (coming from python and ruby) and want to know what is the idiomatic way of calling functions on a struct?

Mostly I want to know if I should use the dot operator to call functions or use my type as one of the arguments. Also is it better to use pointers or not?

  • pointer vs no pointer?
  • dot vs argument? *

I can do it this way?

package main

import "fmt"

func main() {
    me := Person{firstname: "John", lastname: "Doe", age: 40}
    fmt.Println(me.fullname())
}

type Person struct {
    firstname string
    lastname  string
    age       int
}

func (p Person) fullname() string {
    return p.firstname + p.lastname
}

or this way

package main

import "fmt"

func main() {
    me := Person{firstname: "John", lastname: "Doe", age: 40}
    fmt.Println(fullname(&me))
}

type Person struct {
    firstname string
    lastname  string
    age       int
}

func fullname(p *Person) string {
    return p.firstname + p.lastname
}
  • 写回答

1条回答 默认 最新

  • duanqiao0153 2016-05-25 20:13
    关注

    There isn't one correct way of doing this. It's important to understand the differences between the two and apply each where appropriate. Further more, your functions aren't really comparable. In the one case you've defined a function with a receiver of type Person and it is passed by value, meaning a copy of the instance is made and pushed onto the stack. In the other instance the function is stand alone and you pass a Person reference to it. You can also, do pass by reference with an 'instance method' by making the receiving type a pointer.

    So in the first case;

    func (p Person) fullname() string {
        return p.firstname + p.lastname
    }
    

    you call the function like p.fullname() and a copy of p is pushed onto the stack. If you did assignment in this function, p would not be modified, the instance in the scope would be modified. So for setters, or any function that is intended to change the objects state, this isn't an option at all.

    To elaborate on the alternative I was talking about, you could instead do this;

    func (p *Person) fullname() string {
        return p.firstname + p.lastname
    }
    

    Which still allow you to call it on an instance like p.fullname() however, what's passed to the function is a reference of type *Person. So this would be the typical choice for implementing a function that sets a value on a struct.

    Now your second example;

    func fullname(p *Person) string {
        return p.firstname + p.lastname
    }
    

    has no receiver and passes a pointer. Meaning you call it like this fullname(p). The function is not exported so it's only available in the package where it was declared, in this case main. To draw parallels to (potentially) more familiar languages, this is like defining a function in C++ where the other two are defining a 'method' or a function in a class. And the other two would be compared to 'passing by value' or 'passing by reference'. This passes by reference by is no associated to any type.

    In your example I would always use func (p *Person) fullname() string for performance reasons. In my opinion the most appropriate time to use the pass by value alternative func (p Person) fullname() string is when you want to enforce immutability. If you want to do operations where it's better to produce a new object rather than modifying an existing one (a lot of collection libraries operate like this, for example LINQ in C# always produces a new collection and an attempt to modify the collection during a query will result in an exception) then you probably want a value type receiver.

    Hope that helps. I can update with more information if any of this is still the cause of confusion.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 矩阵加法的规则是两个矩阵中对应位置的数的绝对值进行加和
  • ¥15 活动选择题。最多可以参加几个项目?
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)
  • ¥20 怎么在stm32门禁成品上增加查询记录功能
  • ¥15 Source insight编写代码后使用CCS5.2版本import之后,代码跳到注释行里面
  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀