Разбить проект в подпапки

Я хочу разбить свой проект на подпапки.

Я хочу эту структуру кода:

├── main.go
└── models
    └── user.go

Где main.go находится:

package main

import (
  "fmt"
  "./models"
)

func main(){
  fmt.Println(User{"new_user"})

}

И user.go - это:

package models

type User struct {
  Login string
}

Но пользователь не определен в основном пакете, и предупреждение о повышении импорта "импортировано и не используется".

Что я делаю неправильно? Мой проект прост (не такой пример, но только с несколькими файлами (контроллеры и модели)), и я хочу простую структуру.

Может быть, я делаю это совершенно неправильно?

Проблемный проект находится здесь: https://github.com/abonec/go_import_problem

Ответ 1

Недавно я достиг этого, используя модули go.

Golang представил предварительную поддержку opt-in для модулей начиная с версии v1.11.1, которая предназначена для полного устранения, откровенно говоря, абсурдной необходимости $GOPATH. Теперь вы можете иметь не только версионные зависимости в любом обычном каталоге, например, ~/development, но вы также можете иметь нечто похожее на пространства имен и подкаталоги. Вы можете включить эту функцию, вызвав команду go со следующей переменной среды: GO111MODULE=on.

Go v1.11.3 предполагает включение модулей по умолчанию и запланирован на август 2019 года.


Вот пример структуры каталогов (которую вы можете найти обычно на некоторых других языках).

~/Dev/my-app
 ├── src/
 │   ├── one/
 │   │   ├── two/
 │   │   │   └── two.go
 │   │   └── one.go
 │   └── zero.go
 ├── go.mod
 └── app.go

Приложение называется my-app, которое будет именем модуля для app.go Мы определяем это один раз в go.mod и тогда все остальные файлы go в подкаталогах будут автоматически импортироваться, как если бы они были пространством имен.

Учитывая вышесказанное, two.go, предполагая, что он содержит функцию с именем Two, будет импортирован в app.go с помощью my-app/src/one/two.

Вот что вам нужно сделать, чтобы добиться этого:

go.mod

module my-app

two.go

package two

func Two() string {
    return "I'm totally not supposed to be using go modules for this"
}

app.go

package main

import "my-app/src/one/two"

func main() {
    two.Two()
}

Если бы вы two.TheNewFunc() другой файл в два /, то вы просто использовали бы two.TheNewFunc() если вы сделали TheNewFunc() доступным в новом файле.

Я создал очень простое GitHub репо, которое вы можете проверить в качестве демонстрации.

Ответ 2

Ваш импорт должен быть абсолютным:

import "github.com/abonec/go_import_problem/models"

Если вы не хотите экспортировать проект на внешний референт, вы можете сделать:

import "go_import_problem/models"

(То есть: "the name of your project folder accessible by GOPATH/your package" )

См. "Как использовать пользовательские пакеты в golang?".

И вы бы использовали:

models.User

Как указано в Эффективный переход:

Импортер пакета будет использовать это имя для обозначения его содержимого, поэтому экспортированные имена в пакете могут использовать этот факт, чтобы избежать заикания.
( Не использовать нотацию . импорта, что упростит тесты, которые должны выполняться за пределами тестируемого пакета, но в противном случае этого следует избегать.)


kostix добавляет в комментариях:

чтобы повторить, имена пакетов Go всегда абсолютные (то есть нет относительных имен пакетов, ни с ./, ни с ../, ни с чем-нибудь подобным), но , что имена "привязаны" к одной из так называемых рабочих областей, перечисленных в $GOPATH.

Когда Go ищет пакет, он просматривает рабочие области и пытается найти пакет в каждом из них, в порядке.
Поиск не является рекурсивным. И нет, нет необходимости кодировать URL-адреса в пулах пакетов - если вы не хотите, чтобы ваш пакет был общедоступным.

Ответ 3

Вам нужно квалифицировать элементы в пакете по его имени пакета

So

fmt.Println(models.User{"new_user"})

Ответ 4

Разрыв одного проекта во вложенные папки не является рекомендуемым способом структурирования проекта go, поэтому в принципе нет хорошего способа сделать то, что вы хотите.

Если проект действительно большой и слишком громоздкий, чтобы сделать один пакет, рассмотрите его разделение на несколько совершенно разных пакетов, а не на специальные пакеты подкаталогов. Это имеет то преимущество, что заставляет вас думать о ваших внутренних API-интерфейсах.

Ответ 5

Пакеты упоминаются в коде относительно вашей папки "go/src"

└── go
    └── src
        └── myAwesomeProject
            ├── main.go
            └── models
                └── user.go

Так что в main.go

package main

import (
  "fmt"
  "myAwesomeProject/models"
)

Аналогично, пакеты могут ссылаться друг на друга, используя одно и то же соглашение.

Ответ 6

Вы должны использовать импортированные объекты импортированными именами. Например, если вы

import "./models"

со структурой Пользователь должен использовать его как

models.User