How to import/use other struct in the same package but different folder

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

How to import/use other struct in the same package but different folder

问题

我有这样的文件夹结构:

> validations
    > user
        > user.validation.go
    > address
        > address.validation.go

这两个文件的包名是validations

user.validation.go中,我尝试像这样使用地址验证结构:

type UserValidation struct {
   Address AddressValidation // 错误提示:未声明的名称:AddressValidation
}

我已经尝试在结构体之前调用包名,像这样:

type UserValidation struct {
   Address validations.AddressValidation // 错误提示:未声明的名称:validations
}

我还尝试先导入它:

import "example/go-api/validations"

错误提示:AddressValidation未被validations包声明。

英文:

I have folder structure like this:

> validations
    > user
        > user.validation.go
    > address
        > address.validation.go

the package name for those two file is validations

inside user.validation.go I try to use the address validation struct like this:

type UserValidation struct {
   Address AddressValidation // the error says: undeclared name: AddressValidation
}

and I have tried calling package name before struct like this:

type UserValidation struct {
   Address validations.AddressValidation // the error says: undeclared name: validations
}

and I have tried to import it first:

import "example/go-api/validations"

and the error says: AddressValidation not declared by package validations

答案1

得分: 2

在每个文件夹中,你有三个单独的包:

validations
user
address

validations 文件夹只包含其他包,因此无法被有用地导入;它不包含任何具有导出的代码。

user 文件夹中还包含一个名为 validations 的包,可以导入该包以访问导出的 UserValidation 类型。

address 文件夹中也包含一个名为 validations 的包,可以导入该包以访问导出的 AddressValidation 类型。

但是,GoLang 不会将它们视为单个 validations 包。一个“包”是一个命名空间,但是“具有相同名称的包不是相同的命名空间”。它们仍然是单独且不同的包(和命名空间)。

如果 user 文件夹中的 validations 包希望导入 address 文件夹中的 validations 包,它可以这样做,但必须引用该包的完整路径,并且必须为导入进行别名,因为文件夹名称与其包含的包的名称不匹配:

import validations "example/go-api/validations/address"

type UserValidation struct {
   Address validations.AddressValidation
}

这样可以正常工作。

但请注意,由于这涉及别名,该别名可以是任何你喜欢的内容 - 它不必与导入的包的名称匹配。也就是说,以下代码同样有效:

import v "example/go-api/validations/address"

type UserValidation struct {
   Address v.AddressValidation
}

如果项目中的其他包希望引用 UserValidationAddressValidation,它必须导入包含它们的两个单独的 validations 包,并为每个包提供唯一的别名:

import (
   addressValidations "example/go-api/validations/address"
   userValidations "example/go-api/validations/user"
)

然后可以执行类似以下的操作:

var (
   av addressValidations.AddressValidation
   uv userValidations.UserValidation
)

关键在于“文件夹不是组织包内文件的方式”。一个文件夹本身就是一个包。

除非有特定的原因,否则最好遵循以下做法:

  1. 为包命名与包含其文件的文件夹相同。
  2. 在同一项目/模块中使用唯一的包名称。

偶尔会有一些有效的例外情况,例如包名称在两个不同且互斥的上下文中都有意义。也就是说,从这些不同的上下文中没有其他包希望或需要导入具有相同名称的不同包。

我还没有遇到过违反第一条规则的有效例外情况。 How to import/use other struct in the same package but different folder

可能的替代方法

如果你真的想将 UserValidationAddressValidation 保留在单独的包中,你可以将这些包命名为 useraddress(即遵循第一条规则:为它们各自的文件夹命名)。

然后,由于包名为其中的符号提供了地址或用户上下文,你可以将类型重命名为简单的 Validation

你的 user.go 代码将变为:

package user

import "example/go-api/validations/address"

type Validation struct {
   Address address.Validation
}

你的 address.go 代码将变为:

package address

type Validation struct {}

在导入了 useraddress 验证的包中,变量将变为:

import (
   "example/go-api/validations/address"
   "example/go-api/validations/user"
)

var (
   av address.Validation
   uv user.Validation
)

请注意,这不是一种固定的解决方案!在不了解你的具体用例的情况下,我不知道这是否是处理这个特定问题的最佳方式;它只是一种方式的示例。

简而言之:使用文件夹/包名称来帮助为你的包导出的符号添加上下文和含义。

英文:

You have three separate packages in each of these folders:

validations
user
address

The validations folder contains only other packages so is not able to be usefully imported; it contains no code with any exports.

The user folder also contains a package named validations this can usefully imported to access the exported UserValidation type.

The address folder also contains a package named validations this can be usefully imported to access the exported AddressValidation type.

But GoLang does not treat these as all forming a single validations package. A 'package' is a namespace, but packages with the same name are not the same namespace. They all remain separate and distinct packages (and namespaces).

If the validations package in the user folder wishes to import the validations package in the address folder it can do so but must reference the full path to that package and must alias the import since the folder name does not match the name of the package it contains:

import validations "example/go-api/validations/address"

type UserValidation struct {
   Address validations.AddressValidation
}

will work just fine.

But note that since this involves an alias, that alias can be anything you like - it doesn't have to match the name of the imported package. i.e. this is just as valid:

import v "example/go-api/validations/address"

type UserValidation struct {
   Address v.AddressValidation
}

If some other package in your project wishes to reference both UserValidation and AddressValidation it must import both of the separate validations packages that contain them and provide unique aliases for each:

import (
   addressValidations "example/go-api/validations/address"
   userValidations "example/go-api/validations/user"
)

and may then do something like:

var (
   av addressValidations.AddressValidation
   uv userValidations.UserValidation
)

The key to all of this is that folders are not a way of organising files within a package. A folder is a package.

Unless you have a specific reason for doing otherwise it is best to:

  1. Name a package for the folder that contains its files
  2. Use unique names for packages (in the same project/module)

There are occasional, valid exceptions to rule #2, e.g. where a package name makes sense in two different and mutually exclusive contexts. i.e. where no other package would never wish or need to import different packages of the same name from those different contexts.

I've yet to encounter a valid exception to rule #1. How to import/use other struct in the same package but different folder

Possible Alternative Approach

If you really want to keep UserValidation and AddressValidation in separate packages, you could name the packages user and address (i.e. apply rule #1: name each package for their respective folders).

Then, since the package name provides the address or user context for the symbols within them, you can rename the types to simply Validation in each case.

Your user.go code then becomes:

package user

import "example/go-api/validations/address"

type Validation struct {
   Address address.Validation
}

and your address.go code:

package address

type Validation struct {}

and variables in a package that imports both user and address validations become:

import (
   "example/go-api/validations/address"
   "example/go-api/validations/user"
)

var (
   av address.Validation
   uv user.Validation
)

Caveat Coder

This is not a prescription! Without knowing more about your specific use case I have no idea whether this is the best way to skin this particular feline; it is merely an illustration of one way.

In short: use your folder/package names to help add context and meaning to the symbols exported by your packages.

huangapple
  • 本文由 发表于 2022年11月30日 09:54:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/74622077.html
匿名

发表评论

匿名网友

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

确定