This is a creation in Article, where the information may have evolved or changed.
What is a package? Why use a package?
The GO program we've seen so far has only one file, and the file contains a main function and several other functions. In practice, this way of organizing all the code in one file is not feasible. This way of organizing makes it difficult to reuse and maintain code. Package is used to address such issues.
packages are used to organize go source code for better reusability and readability. packages provide a mechanism for code encapsulation, which makes the go application easy to maintain. For example, suppose we are developing an image processing application that provides features such as cropping, sharpening, blurring, and color enhancement. One way to organize your code is to put all the code that implements the same functionality in a separate package. For example, the cropping function can be placed in a separate package, and sharpening can be placed in another package. The advantage of this approach is that the color-enhancing feature may require some sharpening, so the add-in code can simply import (we will discuss the import) sharpening package, using the features provided in it. This way makes the code easier to reuse.
We will gradually create an application that calculates the rectangular area and diagonal.
By building This program, we will better understand the package.
Main function and main package
Each executable go program must contain a main
function. This function is the entry point for executing the program. main
the function should be included in the main
package.
The syntax for specifying that a particular source file belongs to a package is: package packagename
This statement should be placed on the first line of the source file.
Let's start by creating main
functions and main
packages. [工作空间目录]/src
Create a new subdirectory under the directory named geometry
. Create a new folder under this directory geometry.go
.
Write the geometry.go
following code:
//geometry.gopackage main import "fmt"func main() { fmt.Println("Geometrical shape properties")}
package main
This line specifies that the file belongs to the main
package. The import "packagename"
statement is used to import a package, where we import the fmt
package, and the package exports the Println
method ( Translator Note: This method is used to print text to standard output ). Then there is the main
function, which is printed here only Geometrical shape properties
.
Perform go install geometry
compilation of the above program. This command geometry
finds the file containing the function in the directory main
, which is here geometry.go
. Locate and then compile the file and [工作空间目录]/bin
generate a binary file under the directory geometry
(under Windows geometry.exe
). The directory structure is now as follows:
src/ geometry/ geometry.gobin/ geometry
[工作空间目录]/bin/geometry
run the program, where the [workspace directory] needs to be replaced by its own actual directory. This command runs a binary bin
file under the directory geometry
. You should be able to see the following output:
Geometrical shape properties
Create a custom package
Below we will create a rectangle
package that places the functions associated with the rectangle (calculating the area and diagonal of the rectangle) in this package.
The source files that belong to the same package should be placed in a separate folder, and the name of the folder should be the same as the package name in the Go Convention.
So let's geometry
create a subdirectory under the directory rectangle
. All source files placed in this directory should start with a package rectangle
representation that the source files belong to the rectangle
package.
To rectangle
create a new directory rectangle.go
, write the following code:
//rectprops.gopackage rectangleimport "math"func Area(len, wid float64) float64 { area := len * wid return area}func Diagonal(len, wid float64) float64 { diagonal := math.Sqrt((len * len) + (wid * wid)) return diagonal}
In the code above, we implemented two functions Area
and Diagonal
respectively the area and diagonal for the calculation of the rectangle. The area of the rectangle is the product of the length and width. The diagonal of the rectangle is the sum of squares of length and width and then open radical. This calls math
the function in the package Sqrt
to calculate the square root.
Note that the function names Area
Diagonal
of the two functions implemented above are all preceded by uppercase letters. This is necessary and we will soon explain why we need to do so.
Importing Custom Packages
In order to use a custom package we must first import it. The syntax used to import a custom package is: import path
. We must specify path
a [工作空间目录]/src
relative path relative to the directory. Our current directory structure is as follows:
src/ geometry/ geometry.go rectangle/ rectangle.go
The statement import "geometry/rectangle"
indicates that we are importing the rectangle package.
geometry.go
Add the following code in:
//geometry.gopackage main import ( "fmt" "geometry/rectangle" //importing custom package)func main() { var rectLen, rectWidth float64 = 6, 7 fmt.Println("Geometrical shape properties") /*Area function of rectangle package used */ fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth)) /*Diagonal function of rectangle package used */ fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth))}
The above code imports the rectangle
package and uses Area
Diagonal
the and functions to calculate the area and diagonal of the rectangle. The Printf
%.2f
formatting indicator in indicates that only two decimal places are reserved for floating-point numbers. The program output is as follows:
Geometrical shape properties area of rectangle 42.00 diagonal of the rectangle 9.22
Export name
We rectangle
capitalized the two function names Area
and the first letters in the package Diagonal
, which has a special meaning in Go. In Go, any variable name that starts with a capital letter, and the function name is the exported first (exported name). Only names that are exported can be accessed by other packages. Here we need to main
access and function in the package Area
Diagonal
, so capitalize their first letter.
If you change it to, and then rectprops.go
Area(len, wid float64)
change it, the compiler will area(len, wid float64)
geometry.go
rectangle.Area(rectLen, rectWidth)
rectangle.area(rectLen, rectWidth)
Error when you run the program: geometry.go:11: cannot refer to unexported name rectangle.area
. Therefore, if you want to access a function outside the package, you must capitalize its first letter.
init function
Each package can contain a init
function. The function should not have any parameters and return values, and it cannot be explicitly called in our code. The init
function form is as follows:
func init() { }
init
Functions can be used to perform initialization tasks or to verify the correctness of a program before execution begins.
The initialization order of a package is as follows:
- Package-level variables are first initialized
- The
init
function is then called. A package can have multiple init
functions (in one or more files), and their invocation order is the order in which the compiler resolves them.
If a package is imported into another package, the imported package is initialized first.
Although a package may be included more than once, it is initialized only once.
Let's make some changes to our program to understand the init
function.
First rectprops.go
add a function in init
:
//rectprops.gopackage rectangleimport "math" import "fmt"/* * init function added */func init() { fmt.Println("rectangle package initialized")}func Area(len, wid float64) float64 { area := len * wid return area}func Diagonal(len, wid float64) float64 { diagonal := math.Sqrt((len * len) + (wid * wid)) return diagonal}
We have added a simple init
function that only prints: rectangle package initialized
.
Now let's modify the main
package. We know that the rectangle length
and width
should be greater than 0
. We will geometry.go
add init
functions and package-level variables in to do this check.
Modify the geometry.go
following:
//geometry.gopackage main import ( "fmt" "geometry/rectangle" //importing custom package "log")/* * 1. package variables*/var rectLen, rectWidth float64 = 6, 7 /**2. init function to check if length and width are greater than zero*/func init() { println("main package initialized") if rectLen < 0 { log.Fatal("length is less than zero") } if rectWidth < 0 { log.Fatal("width is less than zero") }}func main() { fmt.Println("Geometrical shape properties") fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth)) fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth))}
We have geometry.go
made the following modifications:
- The rectlen and rectwidth variables move from the
main
function to the outside, becoming a package-level variable.
- Add a
init
function. When rectLen
or rectWidth
less 0
, the function takes advantage of log. Fatal Prints a log and terminates the program.
main
The package is initialized in the following order:
- The imported package is initialized first. So the
rectangle
package is initialized first.
- Then initialize the package-level variables: rectlen and rectwidth .
- The init function is called.
- The last
main
function is called.
Run the program with the output as follows:
rectangle package initialized main package initialized Geometrical shape properties area of rectangle 42.00
As expected, the rectangle
function of the package is init
called First, then the package-level variables rectlen and rectwidth are initialized, and then the main
function of the package is init
called, and the function detects rectLen
and rectWidth
is less than 0
, if less than 0
, terminates the program. We will introduce the statements in a separate tutorial if
. Now you can assume that it if rectLen < 0
will detect if rectLen
0
it is less than, and if so, terminate the program. rectWidth
is the same treatment. This means that two conditions are false to continue execution. Finally, the main
function is called.
Let's modify the program again to learn init
the use of the function.
geometry.go
var rectLen, rectWidth float64 = 6, 7
Change this line to var rectLen, rectWidth float64 = -6, 7
. This will rectLen
change to a negative value.
Now run the program and get the following result:
rectangle package initialized main package initialized 2017/04/04 00:28:20 length is less than zero
As above, the rectangle
package is initialized first, then the package main
-level variables and initialization in the package rectLen
rectWidth
. The function of the main
package is then called init
because rectLen
it is less than 0
, so the program length is less than zero
exits after printing.
The code can be downloaded on GitHub.
Use NULL indicator
It is illegal to import only the package in Go and not use it in code. If you do this, the compiler will make an error. The reason for this is to avoid the introduction of too many unused packages, resulting in a significant increase in compilation time. geometry.go
Replace the code in the following code:
//geometry.gopackage main import ( "geometry/rectangle" //importing custom package)func main() {}
The above program will have an error:geometry.go:6: imported and not used: "geometry/rectangle"
However, it is common in the development process to import a package without immediately using it. You can use a null indicator ( _
) to handle this situation.
The following code can avoid throwing the above error:
package mainimport ( "geometry/rectangle" )var _ = rectangle.Area //error silencerfunc main() {}
var _ = rectangle.Area
This line masks the error. We should keep track of these "False silencers" (Error silencer), at the end of development, we should remove these "error silencers", and if the corresponding package is not used, these packages should also be removed. Therefore, it is recommended that you import
write an "error silencer" in the package level after the statement.
Sometimes we import a package just to make sure that the package initializes, and we don't need to use any of the functions or variables in the package. For example, we may need to make sure that rectangle
the function of the package init
is called without intending to use the package anywhere in the code. The null indicator can still handle this situation, as in the following code:
package main import ( _ "geometry/rectangle" )func main() {}
Run the above program and you will get the output: rectangle package initialized
. We successfully initialized the package, even if it was not used anywhere in the code.