英文:
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
}
如果项目中的其他包希望引用 UserValidation
和 AddressValidation
,它必须导入包含它们的两个单独的 validations
包,并为每个包提供唯一的别名:
import (
addressValidations "example/go-api/validations/address"
userValidations "example/go-api/validations/user"
)
然后可以执行类似以下的操作:
var (
av addressValidations.AddressValidation
uv userValidations.UserValidation
)
关键在于“文件夹不是组织包内文件的方式”。一个文件夹本身就是一个包。
除非有特定的原因,否则最好遵循以下做法:
- 为包命名与包含其文件的文件夹相同。
- 在同一项目/模块中使用唯一的包名称。
偶尔会有一些有效的例外情况,例如包名称在两个不同且互斥的上下文中都有意义。也就是说,从这些不同的上下文中没有其他包希望或需要导入具有相同名称的不同包。
我还没有遇到过违反第一条规则的有效例外情况。
可能的替代方法
如果你真的想将 UserValidation
和 AddressValidation
保留在单独的包中,你可以将这些包命名为 user
和 address
(即遵循第一条规则:为它们各自的文件夹命名)。
然后,由于包名为其中的符号提供了地址或用户上下文,你可以将类型重命名为简单的 Validation
。
你的 user.go
代码将变为:
package user
import "example/go-api/validations/address"
type Validation struct {
Address address.Validation
}
你的 address.go
代码将变为:
package address
type Validation struct {}
在导入了 user
和 address
验证的包中,变量将变为:
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:
- Name a package for the folder that contains its files
- 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.
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论