การจัดระเบียบโครงการหลายไฟล์ไป [ปิด]


238

หมายเหตุ: คำถามนี้เกี่ยวข้องกับคำถามนี้แต่สองปีเป็นเวลานานในประวัติศาสตร์ของ Go

วิธีมาตรฐานในการจัดระเบียบโครงการ Go ในระหว่างการพัฒนาคืออะไร?

โครงการของฉันเป็นแพ็คเกจเดียวmypackดังนั้นฉันเดาว่าฉันจะวางไฟล์. go ทั้งหมดไว้ในmypackไดเรกทอรี

แต่แล้วฉันต้องการทดสอบในระหว่างการพัฒนาดังนั้นฉันต้องการอย่างน้อยหนึ่งไฟล์ที่ประกาศmainแพ็คเกจเพื่อที่ฉันจะได้ทำgo run trypack.go

ฉันจะจัดระเบียบสิ่งนี้ได้อย่างไร ฉันต้องทำgo install mypackทุกครั้งที่ฉันต้องการลองหรือไม่?


14
screencast สั้น ๆ นี้น่ากลัว: youtube.com/watch?v=XCsL89YtqCs
Matt

นี่เป็นอีกลิงค์ที่มีประโยชน์ในการทำความเข้าใจวิธีจัดระเบียบโครงการด้วยแพ็คเกจ ทำตามได้ง่ายกว่าวิธีเขียนรหัสอย่างเป็นทางการฉันคิดว่า
IamNaN

สำหรับระบบโมดูล Go ใหม่คำตอบนี้ครอบคลุมโครงสร้างโมดูลการจัดแพคเกจภายในโมดูลไม่ว่าจะมีหลายโมดูลในที่เก็บเดียวหรือไม่ ฯลฯ ในที่สุดเอกสารอินโทร"How to Write Go Code"อย่างเป็นทางการจะได้รับการอัปเดตสำหรับโมดูล แต่นั่นยังไม่เกิดขึ้น (หากคุณยังใหม่กับ Go และโมดูลใหม่ to Go ยังคงคุ้มค่าที่จะอ่านว่าเอกสาร "How to Write Go Code" ก่อนที่จะอ่านเพิ่มเติมเกี่ยวกับโมดูลที่ได้รับจากเอกสารโมดูลส่วนใหญ่ถือว่าคุ้นเคยกับ GOPATH)
general182

คำตอบ:


171

ฉันขอแนะนำให้อ่านหน้านี้ในวิธีการเขียนโค้ด Go

เป็นเอกสารทั้งวิธีการจัดโครงสร้างโครงการของคุณในgo buildวิธีที่เป็นมิตรและวิธีการเขียนการทดสอบ การทดสอบไม่จำเป็นต้องเป็น cmd โดยใช้mainแพ็คเกจ พวกเขาสามารถเป็นชื่อของ TestX ซึ่งเป็นส่วนหนึ่งของแต่ละแพ็คเกจและจากนั้นgo testจะค้นพบพวกมัน

โครงสร้างที่แนะนำในลิงก์นั้นในคำถามของคุณค่อนข้างล้าสมัยไปแล้วในขณะนี้ด้วยการเปิดตัว Go 1 คุณไม่จำเป็นต้องวางpkgไดเรกทอรีsrcอีกต่อไป ไดเรกทอรีที่เกี่ยวข้องกับข้อมูลจำเพาะ 3 รายการเท่านั้นคือ 3 ในรากของ GOPATH: bin, pkg, src ภายใต้ src คุณสามารถวางโครงการของคุณmypackและภายใต้นั่นคือไฟล์. go ทั้งหมดของคุณรวมถึง mypack_test.go

go build จะสร้างเป็น pkg และ bin ระดับราก

ดังนั้น GOPATH ของคุณอาจมีลักษณะเช่นนี้:

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

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

อัปเดต: ตั้งแต่> = ไป 1.11 ระบบโมดูลตอนนี้เป็นส่วนมาตรฐานของการทำเครื่องมือและแนวคิด GOPATH ใกล้จะล้าสมัยแล้ว


26
ใช้ $ HOME แทนที่จะเป็น ~ เมื่อส่งออกตัวแปร
Johan S

6
ทำไม $ HOME ถึงแนะนำมากกว่า ~ เมื่อส่งออกตัวแปร?
425nesp

8
เพราะ ~ ไม่ใช่ตัวแปรเพียงนามแฝง
Pih

6
@ 425nesp โจฮานเข้าใจผิด - ไม่ใช่ เชลล์แตกต่างกันไป แต่bash จะขยายออก~เมื่อตั้งค่าตัวแปรสภาพแวดล้อม ลองด้วยตัวคุณเอง: export BOB=~ && env | grep ^BOBจะให้ผลตอบแทนBOB=/your/homedir
Austin Adams

1
$HOMEทำงานในเปลือกหอยมากขึ้น~ตัวอย่างเช่นในfish
hoijui

60

JDI GOPATHมีข้อมูลที่ถูกต้องเกี่ยวกับการใช้งานของ ฉันจะเพิ่มว่าถ้าคุณตั้งใจจะมีไบนารีเช่นกันคุณอาจต้องการเพิ่มระดับหนึ่งในไดเรกทอรี

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

การทำงานgo build myproj/mypackจะสร้างmypackแพคเกจพร้อมกับการพึ่งพามันการทำงานgo build myproj/myappจะสร้างmyappไบนารีพร้อมกับการพึ่งพาซึ่งอาจรวมถึงmypackห้องสมุด


แน่นอนว่านี่จะสมเหตุสมผลถ้าเขามี cmd หลัก ดูเหมือนว่าเขาเพิ่งสร้างแพ็คเกจห้องสมุด
jdi

50

ฉันได้ศึกษาโครงการ Go หลายโครงการและมีการเปลี่ยนแปลงบ้าง คุณสามารถบอกได้ว่าใครมาจาก C และผู้ที่มาจาก Java เนื่องจากการดัมพ์ก่อนหน้านี้เกี่ยวกับทุกอย่างในไดเรกทอรีรากของโครงการในmainแพ็คเกจและหลังมักจะใส่ทุกอย่างในsrcไดเรกทอรี อย่างไรก็ตามมันก็ไม่เหมาะ แต่ละรายการมีผลกระทบเนื่องจากมีผลกระทบต่อเส้นทางการนำเข้าและวิธีที่ผู้อื่นสามารถนำมาใช้ซ้ำได้

เพื่อให้ได้ผลลัพธ์ที่ดีที่สุดฉันได้ทำตามแนวทางต่อไปนี้

myproj/
  main/
    mypack.go
  mypack.go

ในกรณีที่mypack.goเป็นpackage mypackและmain/mypack.goเป็น package main(ชัด)

หากคุณต้องการไฟล์สนับสนุนเพิ่มเติมคุณมีสองทางเลือก ให้เก็บไว้ในไดเรกทอรีรากหรือวางไฟล์การสนับสนุนส่วนตัวในlibไดเรกทอรีย่อย เช่น

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

หรือ

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

ใส่เฉพาะไฟล์ในlibไดเรกทอรีหากไม่ได้ตั้งใจจะนำเข้าจากโครงการอื่น กล่าวอีกนัยหนึ่งถ้าพวกเขาเป็นไฟล์สนับสนุนส่วนตัว นั่นคือแนวคิดที่อยู่เบื้องหลังlib- เพื่อแยกสาธารณะออกจากส่วนต่อประสานส่วนตัว

การทำสิ่งต่าง ๆ ด้วยวิธีนี้จะช่วยให้คุณมีเส้นทางการนำเข้าที่ดีmyproj.org/mypackเพื่อนำรหัสมาใช้ในโครงการอื่น ๆ ถ้าคุณใช้แล้วไฟล์การสนับสนุนภายในจะมีเส้นทางนำเข้าที่บ่งบอกถึงว่าlibmyproj.org/lib/mysupport

เมื่อมีการสร้างโครงการที่ใช้เช่นmain/mypack go build main/mypackหากคุณมีมากกว่าหนึ่งปฏิบัติการคุณยังสามารถแยกเหล่านั้นภายใต้mainโดยไม่ต้องสร้างโครงการแยกต่างหาก เช่นและmain/myfoo/myfoo.gomain/mybar/mybar.go


14
Idomatic คือการใช้cmd/nameOfMyExecutableไดเรกทอรีย่อยสำหรับแพ็คเกจหลัก (ต้องการเฉพาะcmd/…ถ้าคุณมีหลายคำสั่งดูgolang.org/x/tools/cmd; มิฉะนั้นเป็นเรื่องธรรมดาที่จะสลับไปมาและมีmain.goระดับสูงสุด) วิธีที่คุณมีมันgo installจะสร้างไฟล์ปฏิบัติการ "main" (หรือ "main.exe") นอกจากนี้สำนวนคือการใช้internalไดเรกทอรีย่อยสำหรับแพคเกจย่อยภายในแพคเกจ / โปรแกรมที่ไม่ได้ตั้งใจจะใช้ที่อื่น (เป็นที่คาดว่ารุ่นอนาคตของ Go จะบังคับใช้ไม่มีใครนำเข้าinternalแพคเกจทำเช่นนี้)
เดฟ C

21

ฉันพบว่ามีประโยชน์มากที่จะเข้าใจวิธีการจัดระเบียบโค้ดใน Golang ตอนนี้http://www.golang-book.com/11ของหนังสือเล่มนี้เขียนโดย Caleb Doxsey


13

ดูเหมือนจะไม่มีวิธีมาตรฐานในการจัดระเบียบโครงการ Go แต่https://golang.org/doc/code.htmlระบุวิธีปฏิบัติที่ดีที่สุดสำหรับโครงการส่วนใหญ่ คำตอบของ jdi นั้นดี แต่ถ้าคุณใช้ github หรือ bitbucket และคุณมีไลบรารีเพิ่มเติมด้วยคุณควรสร้างโครงสร้างต่อไปนี้:

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

ด้วยการทำเช่นนี้คุณสามารถมีที่เก็บแยกต่างหากสำหรับ mylib ที่สามารถใช้สำหรับโครงการอื่น ๆ และสามารถเรียกดูได้โดย "go get" โครงการ mypack ของคุณสามารถนำเข้าห้องสมุดของคุณโดยใช้ "github.com/username/mylib" สำหรับข้อมูลเพิ่มเติม:

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


6

เก็บไฟล์ในไดเรกทอรีเดียวกันและใช้package mainในไฟล์ทั้งหมด

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

จากนั้นเรียกใช้:

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

ใช้งานได้อย่างไร? main.go ของคุณจะต้องเป็นแพ็คเกจหลัก lib.go น่าจะอยู่ในแพ็คเกจอื่นแล้วเครื่องมือ go บ่นว่าคุณไม่มีแพ็คเกจสองโฟลเดอร์ในโฟลเดอร์เดียว
I82

1
@ I82Much OP ถามถึงวิธีการแบ่งแพ็คเกจหนึ่งโปรแกรมหลักไปยังไฟล์จำนวนมาก lib.go อยู่ในแพ็คเกจเดียวกันในกรณีนี้
กุสตาฟ

อ่าขอบคุณสำหรับความกระจ่าง
I82

@ กัสตาฟฉันมีคำถามเดียวกัน ดูเหมือนว่าถ้าฉันใส่ package main ใน lib.go ใน main.go ฉันไม่สามารถเรียกใช้ฟังก์ชันที่กำหนดใน lib.go ได้
Qian Chen

@ElgsQianChen วิธีการต้องเป็นแบบสาธารณะต้องเริ่มต้นด้วยตัวพิมพ์ใหญ่ เช่น MyMethod () หรือ MyStruct {... }
กุสตาฟ

6

มาสำรวจกันว่าgo get repository_remote_urlคำสั่งจัดการโครงสร้างโครงการ$GOPATHอย่างไร ถ้าเราทำgo get github.com/gohugoio/hugoมันมันจะโคลนที่เก็บภายใต้

$ GOPATH / src / repository_remote / user_name / project_name


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

นี้เป็นวิธีที่ดีที่จะสร้างของคุณเส้นทางเริ่มต้นโครงการ ทีนี้มาสำรวจกันว่าโปรเจคประเภทใดที่มีอยู่และวิธีการจัดโครงสร้างภายในของมัน โครงการโกลันทั้งหมดในชุมชนสามารถแบ่งได้เป็น

  • Libraries (ไม่มีไบนารีที่ปฏิบัติการได้)
  • Single Project (มีไบนารีที่ปฏิบัติการได้เพียง 1 ตัว)
  • Tooling Projects (มีหลายไบนารีที่ปฏิบัติการได้)

โดยทั่วไปไฟล์โครงการ golang สามารถบรรจุในหลักการออกแบบใด ๆเช่นDDD , POD

โครงการ Go ที่มีอยู่ส่วนใหญ่จะเป็นไปตามPackage Oriented Design นี้

แพ็คเกจ Oriented Designสนับสนุนให้ผู้พัฒนาทำการใช้งานเฉพาะภายในแพ็คเกจของตัวเองเท่านั้นนอกเหนือจาก/internalแพ็คเกจที่แพ็คเกจเหล่านั้นไม่สามารถสื่อสารกันได้


ห้องสมุด

  • โครงการดังกล่าวเป็นไดรเวอร์ฐานข้อมูล , QTสามารถใส่ภายใต้หมวดหมู่นี้
  • ห้องสมุดบางอย่างเช่นสี , ในขณะนี้เป็นไปตามโครงสร้างแบนโดยไม่ต้องแพคเกจอื่น ๆ
  • ส่วนใหญ่ของโครงการห้องสมุดเหล่านี้จัดการแพคเกจที่เรียกว่าภายใน
  • /internal แพคเกจส่วนใหญ่จะใช้เพื่อซ่อนการใช้งานจากโครงการอื่น ๆ
  • ไม่ได้มีไบนารีปฏิบัติการใด ๆ เพื่อให้ไฟล์ที่มีไม่มีหลัก func

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

โครงการเดียว

  • โครงการเช่นhugo , etcdมีfunc หลักเดียวในระดับรากและ
  • เป้าหมายคือการสร้างไบนารีเดียว

โครงการ Tooling

  • โครงการเช่นkubernetes , go-ethereumมีฟังก์ชั่นหลักหลายอย่างภายใต้แพคเกจที่เรียกว่าcmd
  • cmd/ แพคเกจจัดการจำนวนไบนารี (เครื่องมือ) ที่เราต้องการสร้าง

 ~/$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/
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.