Home > Software engineering >  How to import/use other struct in the same package but different folder
How to import/use other struct in the same package but different folder

Time:11-30

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

CodePudding user response:

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. :)

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.

  •  Tags:  
  • go
  • Related