Tổ chức một dự án nhiều tệp [đóng]


237

Lưu ý: câu hỏi này có liên quan đến câu hỏi này , nhưng hai năm là một khoảng thời gian rất dài trong lịch sử Go.

Cách tiêu chuẩn để tổ chức một dự án Go trong quá trình phát triển là gì?

Dự án của tôi là một gói duy nhất mypack, vì vậy tôi đoán rằng tôi đã đặt tất cả các tệp .go vào một mypackthư mục.

Nhưng sau đó, tôi muốn kiểm tra nó trong quá trình phát triển vì vậy tôi cần ít nhất một tệp khai báo maingói, để tôi có thể làmgo run trypack.go

Tôi nên tổ chức việc này như thế nào? Tôi có cần phải làm go install mypackmỗi lần tôi muốn thử không?


14
Đoạn phim ngắn này thật tuyệt vời: youtube.com/watch?v=XCsL89YtqCs
Matt

Đây là một liên kết hữu ích khác để hiểu cách tổ chức một dự án với các gói. Tôi nghĩ dễ theo dõi hơn chính thức Cách viết mã đi tôi nghĩ.
IamNaN

Đối với hệ thống mô-đun Go mới, câu trả lời này bao gồm cấu trúc mô-đun, sắp xếp các gói trong một mô-đun, có hay không có nhiều mô-đun trong một kho lưu trữ, v.v. Cuối cùng, tài liệu giới thiệu "Cách viết mã Go" chính thức sẽ được cập nhật cho các mô-đun , nhưng điều đó chưa xảy ra. .
điển hình182

Câu trả lời:


171

Tôi khuyên bạn nên xem lại trang này về Cách viết mã đi

Nó ghi lại cả cách cấu trúc dự án của bạn một go buildcách thân thiện và cả cách viết bài kiểm tra. Các xét nghiệm không cần phải là cmd khi sử dụng maingói. Chúng có thể chỉ đơn giản là các hàm được đặt tên TestX như là một phần của mỗi gói và sau đó go testsẽ khám phá chúng.

Cấu trúc được đề xuất trong liên kết đó trong câu hỏi của bạn đã hơi lỗi thời, bây giờ với việc phát hành Go 1. Bạn không còn cần phải đặt một pkgthư mục bên dưới src. Chỉ có 3 thư mục liên quan đến thông số kỹ thuật là 3 thư mục gốc trong GOPATH của bạn: bin, pkg, src. Bên dưới src, bạn có thể chỉ cần đặt dự án của mình mypackvà bên dưới đó là tất cả các tệp .go của bạn bao gồm cả mypack_test.go

go build sau đó sẽ xây dựng vào cấp gốc pkg và bin.

Vì vậy, GOPATH của bạn có thể trông như thế này:

~/projects/
    bin/
    pkg/
    src/
      mypack/
        foo.go
        bar.go
        mypack_test.go

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

Cập nhật: kể từ> = Go 1.11, hệ thống Mô-đun hiện là một phần tiêu chuẩn của công cụ và khái niệm GOPATH gần như trở nên lỗi thời.


26
Sử dụng $ HOME thay vì ~ khi xuất biến.
Johan S

6
Tại sao $ HOME được đề xuất hơn ~ khi xuất biến?
425nesp

8
Bởi vì ~ không phải là một biến, chỉ là một bí danh.
Pih

6
@ 425nesp Johan bị nhầm - không phải vậy. Shell khác nhau, nhưng bash mở rộng ~khi thiết lập các biến môi trường , và ví dụ shell shell bourne cũng vậy. Hãy tự thử: export BOB=~ && env | grep ^BOBsẽ mang lạiBOB=/your/homedir
Austin Adams

1
$HOMEsau đó hoạt động trong nhiều vỏ hơn ~, ví dụ như trongfish
hoijui

60

jdi có thông tin đúng liên quan đến việc sử dụng GOPATH. Tôi sẽ thêm rằng nếu bạn có ý định có một nhị phân, bạn có thể muốn thêm một cấp độ bổ sung vào các thư mục.

~/projects/src/
    myproj/
        mypack/
            lib.go
            lib_test.go
            ...
        myapp/
            main.go

chạy go build myproj/mypacksẽ xây dựng mypackgói cùng với các phụ thuộc của nó đang chạy go build myproj/myappsẽ xây dựng myappnhị phân cùng với các phụ thuộc có thể bao gồm mypackthư viện.


Điều này sẽ có ý nghĩa, tất nhiên, nếu anh ta thực sự có một cmd chính. Có vẻ như anh ta chỉ đang tạo ra một gói thư viện.
jdi

49

Tôi đã nghiên cứu một số dự án Go và có một chút biến thể. Bạn có thể nói ai là người đến từ C và ai đến từ Java, vì bãi rác trước đây chỉ là về mọi thứ trong thư mục gốc của dự án trong một maingói và cái sau có xu hướng đặt mọi thứ vào một srcthư mục. Không phải là tối ưu tuy nhiên. Mỗi cái đều có hậu quả vì chúng ảnh hưởng đến đường dẫn nhập khẩu và cách người khác có thể sử dụng lại chúng.

Để có kết quả tốt nhất, tôi đã thực hiện phương pháp sau.

myproj/
  main/
    mypack.go
  mypack.go

Trong trường hợp mypack.gopackage mypackmain/mypack.golà (rõ ràng) package main.

Nếu bạn cần các tập tin hỗ trợ bổ sung, bạn có hai lựa chọn. Hoặc giữ tất cả chúng trong thư mục gốc hoặc đặt các tệp hỗ trợ riêng tư trong libthư mục con. Ví dụ

myproj/
  main/
    mypack.go
  myextras/
    someextra.go
  mypack.go
  mysupport.go

Hoặc là

myproj.org/
  lib/
    mysupport.go
    myextras/
      someextra.go
  main/
    mypack.go
  mypage.go

Chỉ đặt các tệp trong một libthư mục nếu chúng không được dự định nhập bởi dự án khác. Nói cách khác, nếu chúng là các tệp hỗ trợ riêng tư . Đó là ý tưởng đằng sau việc có - libtách công chúng khỏi các giao diện riêng tư.

Làm mọi thứ theo cách này sẽ cung cấp cho bạn một đường dẫn nhập tốt, myproj.org/mypackđể sử dụng lại mã trong các dự án khác. Nếu bạn sử dụng libthì các tệp hỗ trợ nội bộ sẽ có đường dẫn nhập biểu thị điều đó , myproj.org/lib/mysupport.

Khi xây dựng dự án, sử dụng main/mypack, ví dụ go build main/mypack. Nếu bạn có nhiều hơn một thực thi, bạn cũng có thể tách những người bên dưới mainmà không phải tạo các dự án riêng biệt. ví dụ main/myfoo/myfoo.gomain/mybar/mybar.go.


14
Idomatic là sử dụng một cmd/nameOfMyExecutablethư mục con cho gói chính (chỉ cần cmd/…nếu bạn có nhiều lệnh; xem golang.org/x/tools/cmd, nếu không thì việc trao đổi nó xung quanh và có main.goở cấp cao nhất). Cách bạn có nó go installsẽ tạo ra một tệp thực thi "chính" (hoặc "main.exe"). Ngoài ra, thành ngữ là sử dụng một internalthư mục con cho gói phụ bên trong gói / chương trình không được sử dụng ở nơi khác (dự kiến ​​các phiên bản tương lai của Go sẽ thực thi không ai nhập internalgói khác theo cách này).
Dave C


13

Dường như không có cách tổ chức dự án tiêu chuẩn nào nhưng https://golang.org/doc/code.html chỉ định cách thực hành tốt nhất cho hầu hết các dự án. Câu trả lời của jdi là tốt nhưng nếu bạn sử dụng github hoặc bitbucket và bạn cũng có các thư viện bổ sung, bạn nên tạo cấu trúc sau:

~/projects/
bin/
pkg/
src/
  github.com/
    username/
        mypack/
            foo.go
            bar.go
            mypack_test.go
        mylib/
            utillib.go
            utillib_test.go

Bằng cách làm theo cách này, bạn có thể có một kho lưu trữ riêng cho mylib có thể được sử dụng cho các dự án khác và có thể được truy xuất bằng cách "đi lấy". Dự án mypack của bạn có thể nhập thư viện của bạn bằng cách sử dụng "github.com/username/mylib". Để biết thêm thông tin:

http://www.alexvictorchan.com/2014/11/06/go-project-structure/


6

Giữ các tệp trong cùng một thư mục và sử dụng package maintrong tất cả các tệp.

myproj/
   your-program/
      main.go
      lib.go

Sau đó chạy:

~/myproj/your-program$ go build && ./your-program

Làm thế nào điều này có thể làm việc? Main.go của bạn cần phải là gói chính; có lẽ lib.go nằm trong một gói khác, sau đó công cụ go phàn nàn rằng bạn không thể có hai gói trong một thư mục.
I82Much

1
@ I82Much OP yêu cầu cách chia một gói, chương trình chính cho nhiều tệp. lib.go là trong cùng một gói trong trường hợp này.
Gustav

Ah cảm ơn đã làm rõ.
I82Much

@Gustav, tôi có cùng một câu hỏi. Có vẻ như nếu tôi đặt gói chính trong lib.go, trong main.go, tôi không thể gọi các hàm được định nghĩa trong lib.go.
Qian Chen

@ElgsQianChen Các phương thức cần được công khai, nó phải bắt đầu bằng chữ in hoa. Ví dụ: MyMethod () hoặc MySturation {...}.
Gustav

6

Hãy khám phá cách go get repository_remote_urllệnh quản lý cấu trúc dự án $GOPATH. Nếu chúng ta làm, go get github.com/gohugoio/hugonó sẽ sao chép kho lưu trữ bên dưới

$ GOPATH / src / repository_remote / user_name / project_name


$ GOPATH / src / github.com/gohugoio/hugo

Đây là một cách hay để tạo đường dẫn dự án ban đầu của bạn . Bây giờ chúng ta hãy khám phá các loại dự án ngoài kia và cách cấu trúc bên trong của chúng được tổ chức. Tất cả các dự án golang trong cộng đồng có thể được phân loại theo

  • Libraries (không có tệp nhị phân thực thi)
  • Single Project (chỉ chứa 1 tệp nhị phân thực thi)
  • Tooling Projects (chứa nhiều tệp nhị phân thực thi)

Nói chung các tệp dự án golang có thể được đóng gói theo bất kỳ nguyên tắc thiết kế nào như DDD , POD

Hầu hết các dự án đi có sẵn đều tuân theo Thiết kế hướng theo gói này

Thiết kế hướng theo gói khuyến khích nhà phát triển chỉ giữ việc triển khai bên trong các gói riêng của mình, ngoài /internalgói mà các gói đó không thể giao tiếp với nhau


Thư viện

  • Các dự án như trình điều khiển cơ sở dữ liệu , qt có thể đặt trong danh mục này.
  • Một số thư viện như màu sắc , hiện theo cấu trúc phẳng mà không có gói nào khác.
  • Hầu hết các dự án thư viện này quản lý một gói được gọi là nội bộ .
  • /internal gói chủ yếu được sử dụng để ẩn việc thực hiện từ các dự án khác.
  • Không có bất kỳ nhị phân thực thi nào, vì vậy không có tệp nào chứa func chính .

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              internal/
              other_pkg/

Dự án đơn

  • Các dự án như hugo , vân vân có một chức năng chính duy nhất ở cấp gốc và.
  • Mục tiêu là tạo một nhị phân đơn

Dự án dụng cụ

  • Các dự án như kubernetes , go-ethereumnhiều func chính được tổ chức theo gói gọi là cmd
  • cmd/ gói quản lý số lượng nhị phân (công cụ) mà chúng tôi muốn xây dựng

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              cmd/
                binary_one/
                   main.go
                binary_two/
                   main.go
                binary_three/
                   main.go
              other_pkg/
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.