如何在Go包和文件夹中组织代码结构?

huangapple go评论76阅读模式
英文:

How to structure code in Go packages and folders?

问题

我已经阅读了各种涵盖这个问题的文章,有很多不同的方法。我刚开始学习Go,想学习最佳实践,而不是一开始就采用一些不好的风格。

作为来自有类的语言的人,我试图在学习Go这样的新语言时不应用我多年来学到的所有东西。

这就带出了我的第一个问题:在Go中,将程序结构化为包和文件夹被认为是一种好的风格吗?

根据我目前的阅读,有些人推荐这样做,所以我选择了这样的结构(我的实际程序要大得多,因此适合“将代码移到包中”的方法):

.
├── bin
│   └── helloworld
└── src
    ├── github.com
    │   ├── SOMEUSER
    │   │   └── helloworld
    │   │       ├── main.go
    │   │       ├── main_test.go
    │   │       ├── greeter
    │   │       │   └── talker.go
    │   │       └── person.go

所以你可以看到,我将一些新代码移到了一个单独的包中,这种情况下是greeter。我在我的main.go文件中导入了这个包(我已经多次阅读到这种方法比使用import ./greeter更好):

package main

import "github.com/SOMEUSER/helloworld/greeter"

func main() {
    greeter.Hello()
}

然后在我的greeter包中调用Hello()函数。
到目前为止还不错。

但是现在出现了我的实际问题(假设上述结构是推荐的Go代码结构方式):

我如何使用在main包的任何文件中声明的任何函数、结构等(在这里我对这种方式是否可行有一些严重的疑问,没有恶意)?

假设我在person.go中声明了一些结构体,叫做Person。这个结构体现在在我的应用程序的几个部分中都被使用,而且在我的包中也使用它会很好,像这样:

package greeter

import "fmt"

func Hello() {
    p := Person{Name: "Steve"}
    fmt.Println(p.Name)
}

尝试构建时,会抛出undefined: Person错误。

如果你能指点我正确的方向,并告诉我在Go中推荐的方式和风格是如何处理这个问题的,我将非常感谢。

英文:

I have read all kinds of articles covering this issue and there are a lot of different approaches out there.
I'm new to Go and I'm trying to learn the best practices instead of picking up some bad styles right in the beginning.

Coming from languages that have classes, I'm trying not to apply everything I've learnt over the years when learning a new language like Go.

Which brings up my first point: Is it considered a good style in Go to structure you program in packages and folders?

From what I've read so far, some people recommend doing that, so I went for a structure like this (my actual program is much bigger and therefor qualifies for the 'move code to packages' approach):

.
├── bin
│   └── helloworld
└── src
    ├── github.com
    │   ├── SOMEUSER
    │   │   └── helloworld
    │   │       ├── main.go
    │   │       ├── main_test.go
    │   │       ├── greeter
    │   │       │   └── talker.go
    │   │       └── person.go

So as you can see I moved some new code to a separate package which in this case would be greeter. I import this package in my main.go file (I've read multiple times already that this approach is recommended instead of doing the import like import ./greeter) :

package main

import "github.com/SOMEUSER/helloworld/greeter"

func main() {
	greeter.Hello()
}

which then calls the function Hello() in my greeter package.
So far so good.

But here comes my actual question (assuming that the above structure would be the recommended way to structure code in Go):

How can I now use any function, struct, etc. which was declared in any of the files in my main package (here I have some serious doubts if this would be the way to go, no pun intended)?

So let's assume I declared some struct in person.go called Person. This struct is now used at several parts of my application, and it'd be good to also use it in my included (local) package, like this:

package greeter

import "fmt"

func Hello() {
	p := Person{Name: "Steve"}
	fmt.Println(p.Name)
}

When trying to build this, it throws an undefined: Person error.

If you could point me in the right direction and enlighten me about the recommended way and style how this is approached in Go, I'd be very thankful.

答案1

得分: 2

要使用Person结构体,您需要导入github.com/SOMEUSER/helloworld包,并像main.Person一样使用它。
然而,这是不可能的,因为您不能导入一个main包,这会创建循环依赖。

通常,我将以下代码导出到子包中:

  • 与包完全无关的辅助函数
  • 可以作为第三方库的独立部分
  • main代码相关但不依赖于main代码的部分

现在,请记住这实际上是一个复杂性问题。如果文件很多但复杂性很低,就不需要使用子包。

英文:

To use the Person struct, you would need to import the github.com/SOMEUSER/helloworld package and use it like main.Person.
However, it isn't possible because you can't import a main package and it would create a circular depedency.

Generally, I export into sub-packages the following code :

  • Helpers completely unrelated to the package
  • Part that are independant and could be a third-party library
  • Part that are related but don't have dependancies on main code

Now, keep in mind that it really is a question of complexity. Having many files but low complexity doesn't justify a subpackage.

答案2

得分: 1

这里有两个解决方案:

1)将代码放回主包,直到你知道如何处理它(这是我的建议)。

2)创建一个人员包,定义Person类型,并将该包导入到两个地方。我认为person.Person这样的命名很愚蠢,所以我不会这样做。database.Person或server.Person对我来说更有意义。我的意思是,在那一点上,一切都取决于你如何读取、写入和存储Person,而这一点还不清楚。

英文:

There are two "solutions" here.

  1. Put the code back in the main package until you know what to do with it (which is my recommendation)

  2. Create a person package defining the Person type and import that package into both. I think person.Person is silly, which is why I wouldn't do this. database.Person or server.Person makes more sense to me. I mean at that point it all comes down to how you're reading, writing and storing Person, and that's unclear.

huangapple
  • 本文由 发表于 2016年3月3日 17:31:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/35768158.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定