Cara mengimpor paket lokal tanpa gopath


171

Saya telah menggunakan GOPATHtetapi untuk masalah saat ini saya menghadapinya tidak membantu. Saya ingin dapat membuat paket yang khusus untuk proyek:

myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go

Saya mencoba beberapa cara tetapi bagaimana saya bisa mulai package1.gobekerja di dan binary1.goatau binary2.gosebagainya?

Sebagai contoh; Saya ingin dapat import "package1"dan kemudian dapat menjalankan go build binary1.godan semuanya berfungsi dengan baik tanpa kesalahan dilemparkan bahwa paket tidak dapat ditemukan di GOROOTatau GOPATH. Alasan mengapa saya memerlukan fungsionalitas semacam ini adalah untuk proyek skala besar; Saya tidak ingin harus merujuk beberapa paket lain atau menyimpannya dalam satu file besar.


2
Anda seharusnya meletakkan file sumber untuk setiap biner ke direktori sendiri.
fuz

Semua .gofile dalam direktori tunggal adalah bagian dari paket yang sama, dan Anda tidak perlu importfile dalam paket yang sama (yaitu direktori yang sama). Anda menyebutkan bekerja di luar GOPATH, yang merupakan salah satu kemampuan sistem modul Go yang baru. Jawaban ini mencakup struktur modul, mengimpor paket lokal, mengatur paket dalam suatu modul, apakah memiliki beberapa modul dalam repositori tunggal, dll.
typical182

3
Dan perilaku ini tidak masalah dengan semua orang? Bahwa Anda pada dasarnya tidak dapat mengimpor sub-paket lokal Anda kecuali jika Anda menentukan keseluruhan git/repo/to/my/projectpath? Saya hanya tidak melihat alasan mengapa ada orang yang menginginkan perilaku ini. Bagaimana jika Anda memindahkan proyek Anda ke lokasi lain (yaitu gambar Docker), Anda perlu mengubah semua jalur lagi? Saya mencari jawaban mengapa ini sangat rumit.
milosmns

@milosmns lihat jawaban saya stackoverflow.com/a/60915633/175071
Timo Huovinen

Jawaban:


176

Ringkasan manajemen ketergantungan Go:

  • vgo jika versi go Anda adalah: x >= go 1.11
  • depatau vendorjika versi go Anda adalah:go 1.6 >= x < go 1.11
  • Secara manual jika versi go Anda adalah: x < go 1.6

Sunting 3: Go 1.11 memiliki fitur vgoyang akan diganti dep .

Untuk menggunakan vgo, lihat dokumentasi Modul . TLDR di bawah ini:

export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build

Metode ini membuat file yang disebut go.moddi direktori proyek Anda. Anda kemudian dapat membangun proyek Anda dengan go build. Jika GO111MODULE=autodiatur, maka proyek Anda tidak dapat masuk $GOPATH.


Sunting 2: Metode pembatalan masih valid dan berfungsi tanpa masalah. vendorsebagian besar merupakan proses manual, karena ini depdan vgodibuat.


Sunting 1: Sementara cara lama saya berfungsi, ini bukan lagi cara yang "benar" untuk melakukannya. Anda harus menggunakan kemampuan vendorvgo ,, atau dep(untuk saat ini) yang diaktifkan secara default di Go 1.6; lihat . Anda pada dasarnya menambahkan paket "eksternal" atau "tergantung" di dalam vendordirektori; saat dikompilasi, kompiler akan menggunakan paket-paket ini terlebih dahulu.


Ditemukan. Saya dapat mengimpor paket lokal dengan GOPATHmembuat subfolder package1kemudian mengimpor dengan import "./package1"in binary1.godan binary2.goskrip seperti ini:

binary1.go

...
import (
        "./package1"
      )
...

Jadi struktur direktori saya saat ini terlihat seperti ini:

myproject/
├── binary1.go
├── binary2.go
├── package1/
   └── package1.go
└── package2.go

Saya juga harus mencatat bahwa jalur relatif (setidaknya dalam go 1.5) juga berfungsi; sebagai contoh:

import "../packageX"

4
Itu berfungsi baik sampai Anda memiliki dua subfolder dengan satu merujuk ke yang lain. Sebagai contoh, jika package2 juga merupakan subfolder dan diperlukan package1, sistem akan rusak.
Carl

7
import "../package1"
Felix Rabe

12
Jalur impor relatif adalah ide yang buruk .
Dave C

1
jika #golang memberikan 'namespace', saya dapat setuju dengan Anda bahwa 'jalur impor relatif' atau 'sub-paket' adalah ide yang buruk '.
mission.liao

1
Nama fungsi harus dimulai dengan kata kunci
Capitilized

71

Tidak ada yang namanya "paket lokal". Organisasi paket pada disk bersifat ortogonal untuk setiap hubungan orangtua / anak paket. Satu-satunya hierarki nyata yang dibentuk oleh paket adalah pohon dependensi, yang dalam kasus umum tidak mencerminkan pohon direktori.

Gunakan saja

import "myproject/packageN"

dan jangan melawan sistem build tanpa alasan yang jelas. Menyimpan selusin karakter per impor dalam program non-sepele bukan alasan yang baik, karena, misalnya, proyek dengan jalur impor relatif tidak dapat diterima.

Konsep jalur impor memiliki beberapa properti penting:

  • Jalur impor dapat menjadi unik secara global.
  • Sehubungan dengan GOPATH, jalur impor dapat diterjemahkan secara jelas ke jalur direktori.
  • Setiap jalur direktori di bawah GOPATH dapat secara jelas diterjemahkan ke jalur impor.

Semua hal di atas hancur dengan menggunakan jalur impor relatif. Jangan lakukan itu.

PS: Ada beberapa tempat dalam kode lama dalam tes kompiler Go yang menggunakan impor relatif. ATM, ini adalah satu-satunya alasan mengapa impor relatif didukung sama sekali.


2
Saya sarankan melihat video intro ini untuk pemahaman yang lebih baik tentang paket dan GOPATH . youtube.com/watch?v=XCsL89YtqCs
Joshua Pinter

7
Saya pikir ini saran yang buruk. Misalnya, jika Anda menggunakan gopkg.in untuk versi, Anda kurang beruntung dengan jalur impor absolut untuk pakage "mini" Anda, seperti dijelaskan di atas. Entah Anda memecahkan sumber repo atau yang versi menjadi tidak berguna.
Greg

import "myproject/packageN". myprojectApakah nama folder yang menampung proyek saya?
Securecurve

Itu benar-benar salah, bagaimana cara menggunakannya dengan repositori pribadi sekarang?
agilob

44

Mungkin Anda mencoba memodulasi paket Anda. Saya berasumsi itu package1dan package2, dengan cara, bagian dari paket yang sama tetapi untuk keterbacaan Anda membaginya menjadi beberapa file.

Jika case sebelumnya milik Anda, Anda bisa menggunakan nama paket yang sama ke dalam file-file multipel dan itu akan seperti jika ada file yang sama.

Ini adalah sebuah contoh:

add.go

package math

func add(n1, n2 int) int {
   return n1 + n2
}

kurangi.go

package math

func subtract(n1, n2 int) int {
    return n1 - n2
}

donothing.go

package math

func donothing(n1, n2 int) int {
    s := add(n1, n2)
    s = subtract(n1, n2)
    return s
}

Saya bukan ahli Go dan ini adalah posting pertama saya di StackOveflow, jadi jika Anda memiliki saran, itu akan diterima dengan baik.


23

Saya memiliki masalah yang serupa dan solusi yang saya gunakan saat ini menggunakan modul Go 1.11. Saya memiliki struktur berikut

- projects
  - go.mod
  - go.sum
  - project1
    - main.go
  - project2
    - main.go
  - package1
    - lib.go
  - package2
    - lib.go

Dan saya dapat mengimpor package1 dan package2 dari project1 dan project2 dengan menggunakan

import (
    "projects/package1"
    "projects/package2"
)

Setelah berlari go mod init projects. Saya dapat menggunakan go builddari direktori project1 dan project2 atau saya dapat melakukannya go build -o project1/exe project1/*.godari direktori proyek.

Kelemahan dari metode ini adalah bahwa semua proyek Anda pada akhirnya berbagi daftar ketergantungan yang sama di go.mod. Saya masih mencari solusi untuk masalah ini, tetapi sepertinya itu mungkin mendasar.


9

Sejak diperkenalkannya go.mod , saya pikir manajemen paket lokal dan eksternal menjadi lebih mudah. Menggunakan go.mod , dimungkinkan untuk memiliki proyek di luar GOPATH juga.

Paket impor lokal:

Buat folder demoproject dan jalankan perintah berikut untuk menghasilkan file go.mod

go mod init demoproject

Saya memiliki struktur proyek seperti di bawah ini di dalam direktori demoproject .

├── go.mod
└── src
    ├── main.go
    └── model
        └── model.go

Untuk tujuan demo, masukkan kode berikut dalam file model.go .

package model

type Employee struct {
    Id          int32
    FirstName   string
    LastName    string
    BadgeNumber int32
}

Di main.go , saya mengimpor model Karyawan dengan merujuk ke "demoproject / src / model"

package main

import (
    "demoproject/src/model"
    "fmt"
)

func main() {
    fmt.Printf("Main Function")

    var employee = model.Employee{
        Id:          1,
        FirstName:   "First name",
        LastName:    "Last Name",
        BadgeNumber: 1000,
    }
    fmt.Printf(employee.FirstName)
}

Impor ketergantungan eksternal:

Jalankan saja go getperintah di dalam direktori proyek.

Sebagai contoh:

go get -u google.golang.org/grpc

Itu harus mencakup ketergantungan modul dalam file go.mod

module demoproject

go 1.13

require (
    golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
    golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
    golang.org/x/text v0.3.2 // indirect
    google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 // indirect
    google.golang.org/grpc v1.26.0 // indirect
)

https://blog.golang.org/using-go-modules


can't load package: package .: no Go files in...(buka build di folder go.mod)
Sebi2020

Larangan seperti itu tetapi butuh waktu yang memalukan bagi saya untuk menemukan jawabannya dan pos Anda adalah yang paling mudah dibaca dan bermanfaat. Terima kasih!
Harold Cavendish

8

Untuk menambahkan paket "lokal" ke proyek Anda, tambahkan folder (misalnya "package_name"). Dan letakkan file implementasi Anda di folder itu.

src/github.com/GithubUser/myproject/
 ├── main.go
 └───package_name
       └── whatever_name1.go
       └── whatever_name2.go

Dalam package mainmelakukan ini:

import "github.com/GithubUser/myproject/package_name"

Di mana package_namenama folder dan itu harus cocok dengan nama paket yang digunakan dalam file whatever_name1.go dan whatever_name2.go. Dengan kata lain semua file dengan sub-direktori harus dari paket yang sama.

Anda selanjutnya dapat membuat sarang lebih banyak subdirektori selama Anda menentukan keseluruhan path ke folder induk dalam impor.


2
Ini adalah saran yang bagus, kecuali bahwa selama panik kernel jejak stack yang dibuang dari binary menunjukkan jalur github.com misalnya, tidak selalu perilaku yang paling diinginkan. Ada beberapa tanda untuk menekan ini, tetapi seharusnya tidak perlu hanya untuk mencapai organisasi paket yang sederhana, dan saya menemukan bahwa itu kadang gagal.
Kenny Powers

package myproject/package_name is not in GOROOT (/usr/lib/go-1.14/src/myproject/package_name)
Sebi2020

3

Kamu bisa memakai replace

go modo init example.com/my/foo

foo / go.mod

module example.com/my/foo

go 1.14

replace example.com/my/bar => /path/to/bar

require example.com/my/bar v1.0.0

foo / main.go

package main
import "example.com/bar"

func main() {
    bar.MyFunc()
}

bar / go.mod

module github.com/my/bar

go 1.14

bar / fn.go

package github.com/my/bar

import "fmt"

func MyFunc() {
    fmt.Printf("hello")
}

Mengimpor paket lokal sama seperti mengimpor pacakge eksternal

kecuali di dalam file go.mod Anda mengganti nama paket eksternal dengan folder lokal.

Path ke folder bisa penuh atau relatif "/ path / to / bar" atau "../bar"

https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive https://thewebivore.com/using-replace-in-go-mod-to-point -untuk-modul-lokal Anda /

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.