首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >设计Go包:什么时候我应该定义类型的方法?

设计Go包:什么时候我应该定义类型的方法?
EN

Stack Overflow用户
提问于 2014-09-02 21:12:41
回答 3查看 185关注 0票数 3

假设我有一个类型type T int,并且我想要定义一个逻辑来对这个类型进行操作。

我应该使用什么抽象以及何时使用?

  • 在该类型上定义方法: func ( t ) someLogic() { // .}
  • 定义函数: 漏斗状体感( t) { // .}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-09-03 02:56:28

有些情况下,您倾向于使用方法:

  • 对接收方进行变异:修改对象字段的事务通常是方法。对于您的用户来说,x.Foo修改X并不比Foo(x)修改X更令人惊讶。
  • 通过接收方的副作用:事物通常是类型上的方法,如果它们以更微妙的方式对对象/通过对象产生副作用,比如写入作为struct一部分的网络连接,或者通过指针或切片等在结构中写入。
  • 访问私有字段的:理论上说,同一包中的任何东西都可以看到对象的未导出字段,但更常见的是,只有对象的构造函数和方法可以。让其他东西查看未导出的字段,有点像拥有C++ friend的字段。
  • 满足接口所必需的:仅限方法可以是接口的一部分,因此您可能需要将某些东西作为只满足接口的方法。例如,彼得·伯贡的围棋介绍type openWeatherMap定义为带有方法的空结构,而不是函数,只是为了满足与其他非空结构实现相同的weatherProvider接口。
    • 测试顽固性:作为上述情况的特例,有时接口会帮助测试用的存根对象,因此即使没有状态,存根实现也可能必须是方法。

有些地方您倾向于使用函数:

  • Constructors: func NewFoo(...) (*Foo)是一个函数,而不是一个方法。Go没有构造函数的概念,所以它必须是这样的。
  • 运行在接口或基本类型上的:您不能在interface或基本类型上添加方法(除非您使用type使它们成为一个新类型)。因此,strings.Splitreflect.DeepEqual必须是函数。而且,io.Copy必须是一个函数,因为它不能仅仅在ReaderWriter上定义一个方法。请注意,它们不会声明一个新类型(例如,strings.MyString),以避免无法对基本类型执行方法。
  • 将功能从超大类型或包中移出:有时会积累大量功能(比如某些Web应用程序中的UserPage ),这会损害可读性或组织,甚至会导致结构性问题(例如,如果更难避免循环进口)。从不改变接收方、访问未导出字段等方法中创建一个非方法,可能是将其代码“向上”移动到应用程序的更高层或"over“到另一种类型/包的重构步骤,或者独立功能只是它最自然的长期位置。(对于史蒂夫·弗兰西亚在谈论他的围棋错误时包括了雨果中的一个例子,我给出了一些建议。)
  • 便利性“只需使用默认值”函数:--如果您的用户可能希望以一种快速的方式使用“默认值”对象值,而不显式地创建对象,则可以公开这样做的函数,通常与对象方法同名。例如,http.ListenAndServe()是一个包级函数,它生成一个普通的http.Server并在其上调用ListenAndServe
  • 传递行为的函数:有时不需要定义类型和接口,只为了传递功能,而一个裸函数就足够了,比如在http.HandleFunc()template.Funcs()中,或者注册go vet检查等等。别逼我。
  • 函数--如果面向对象是强制的:说,如果您的main()init()调用了一些助手,那么它们会更干净,或者您的私有函数不会查看任何对象字段,而且永远也不会。同样,如果在您的情况下,您没有从OO (àla type Application struct{...})中获得任何东西,那么您不必强迫它。

当有疑问时,如果某物是导出API的一部分,并且有一个自然的选择来附加它的类型,那么就让它成为一个方法。但是,不要扭曲您的设计(将关注点拉到您可以分离的类型或包中),只是为了某种东西可以成为一种方法。Writers不WriteJSON;如果它们实现了一个,就很难实现。相反,您可以通过其他地方的函数json.NewEncoder(w io.Writer)将JSON功能添加到json.NewEncoder(w io.Writer)中。

如果您仍然不确定,首先编写文档以便清晰地读取文档,然后使代码自然地读取(o.Verb()o.Attrib()),然后按照感觉正确的方式进行,而不会过多地使用它,因为您通常可以稍后重新排列它。

票数 5
EN

Stack Overflow用户

发布于 2014-09-02 21:17:25

如果您正在操作对象的内部secrets,请使用该方法

代码语言:javascript
运行
复制
   (T *t) func someLogic() {
      t.mu.Lock()
      ...
   }

如果使用对象的public interface,则使用该函数

代码语言:javascript
运行
复制
  func somelogic(T *t) {
      t.DoThis()
      t.DoThat()
     }
票数 3
EN

Stack Overflow用户

发布于 2014-09-03 03:32:05

如果要更改T对象,请使用

代码语言:javascript
运行
复制
 func (t *T) someLogic() {
 // ...
 } 

如果您不更改T对象,并且希望使用原始对象方式,请使用

代码语言:javascript
运行
复制
 func (t T) someLogic() {
 // ...
 }

但是请记住,这将生成一个调用someLogic的临时对象T

如果您喜欢c语言的方式,请使用

代码语言:javascript
运行
复制
 func somelogic(t T) {
      t.DoThis()
      t.DoThat()
 }

代码语言:javascript
运行
复制
   func somelogic(t T) {
      t.DoThis()
      t.DoThat()
     }

还有一件事,就是将var隐藏在golang中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25632483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档