Chapter 10 packages and tools
Now any small program may contain 10000 functions, but we can't build them one by one. Most of them come from others. These functions are reused in a way similar to packages and modules
There are more than 100 go language packages. You can use go list std wc -l to view them in the terminal. Open source packages can be found at http://godoc.com Org
go comes with a toolkit with various gadgets to simplify workspace and package management
10.1 package introduction
The package allows us to understand and update the code in a modular way. At the same time, the package can realize the encapsulation feature, so as not to make the code messy, but also facilitate our global distribution. The Go language package compiles quickly because it has three language features: 1 The imported package needs to be explicitly declared at the beginning of the file, so that the compiler does not need to read and analyze the whole source file to judge the dependency of the package. 2 The circular dependency of packages is prohibited. The relationship between packages is a directed acyclic graph. Each package can be compiled independently and may be compiled concurrently. 3 The target file of the compiled package not only records the export information of the package itself, but also records the dependencies of the package
10.2 import path
Packages are usually imported automatically through import. For packages of non-standard libraries, the path address of the Internet should be written, such as the HTML parser maintained by the Go team and a popular MySQL driver maintained by a third party
import ( "fmt" "math/rand" "encoding/json" "golang.org/x/net/html" "github.com/go-sql-driver/mysql" )
10.3 package declaration
Each Go source file must have a package declaration statement at the beginning, which is the identifier when imported by other packages
Access package members by package name
package main import ( "fmt" "math/rand" ) func main() { fmt.Println(rand.Int()) }
Usually, the import path of a package is the package name, but they can have the same name, but their paths may be different
There are three exceptions to using the package name as the last paragraph of the import path, 1 The path of the main package itself is irrelevant, 2 Test package, 3 Add version number information after the import path, such as "gopkg.in/yaml.v2"
10.4 import declaration
Import can be used to import one by one, together, or in groups
import ( "fmt" "html/template" "os" "golang.org/x/net/html" "golang.org/x/net/ipv4" )
If two packages have the same name and need to be renamed during import, this naming will only work in the current file
import ( "crypto/rand" mrand "math/rand" // alternative name mrand avoids conflict )
Renaming has three advantages: one is to divide the time zone into duplicate name packages; the other is to simplify the complex package names and shorten the complex package names; the third is to avoid confusion with the duplicate name variables in the package
The circular import compiler will prompt an error
10.5 anonymous import of packages
If we import a package but do not use it, it will lead to compilation errors. However, sometimes we want to take advantage of the side effects of importing a package: it calculates the package level initialization expression and executes the init initialization function of the imported package. We need to suppress the unused import error. We can use it_ To rename the imported package_ Is a blank identifier and cannot be accessed
import _ "image/png"
This is called anonymous import of packages. It is usually used to implement a compile time mechanism, and then selectively import additional packages at the main program entry. Let's take a look at its features and how it works
package main import ( "fmt" "image" "image/jpeg" "io" "os" ) func main() { if err := toJPEG(os.Stdin, os.Stdout); err != nil { fmt.Fprintf(os.Stderr, "jpeg:%v\n", err) os.Exit(1) } } func toJPEG(in io.Reader, out io.Reader) error { img, kind, err := image.Decode(in) if err != { return err } fmt.Fprintln(os.Stderr,"Input format =",kind) return jpeg.Encode(out,img,&jpeg.Options{Quality: 95}) }
If we give it an appropriate input, it can be successfully converted to output
$ go build gopl.io/ch3/mandelbrot $ go build gopl.io/ch10/jpeg $ ./mandelbrot | ./jpeg >mandelbrot.jpg Input format = png
If there is no anonymous import, it can compile, but it will not output correctly
$ go build gopl.io/ch10/jpeg $ ./mandelbrot | ./jpeg >mandelbrot.jpg jpeg: image: unknown format
Here is how the code works
package png // image/png func Decode(r io.Reader) (image.Image, error) func DecodeConfig(r io.Reader) (image.Config, error) func init() { const pngHeader = "\x89PNG\r\n\x1a\n" image.RegisterFormat("png", pngHeader, Decode, DecodeConfig) }
The final effect is that the main program only needs to anonymously import a specific image driver package to use image Decode decodes the image in the corresponding format
The database package database/sql also adopts a similar technology, so that users can choose to import database drivers according to their needs, such as:
import ( "database/sql" _ "github.com/lib/pq" // enable support for Postgres _ "github.com/go-sql-driver/mysql" // enable support for MySQL ) db, err = sql.Open("postgres", dbname) // OK db, err = sql.Open("mysql", dbname) // OK db, err = sql.Open("sqlite3", dbname) // returns error: unknown driver "sqlite3"
10.6 package and naming
When creating a package, it is generally named with a short name; Try not to use the name of local variable; It is generally singular, but it can also be plural with other considerations
When designing package names, you need to consider how package names and members work together, as shown in the following example:
bytes.Equal flag.Int hettp.Get json.Marshal
Let's look at the naming pattern of strings. Strings provides various operations on strings
package strings func Index(needle, haystack string) int type Replacer struct{ /* ... */ } func NewReplacer(oldnew ...string) *Replacer type Reader struct{ /* ... */ } func NewReader(s string) *Reader
strings. Index \ strings. Replacement and so on are all operations
Other packages may only describe a single data type, such as html/template and math/rand. They only expose a main data structure and its related methods, and a function named New is used to create an instance
package rand // "math/rand" type Rand struct{ /* ... */ } func New(source Source) *Rand
It may also lead to repetition of some names, such as template Template or Rand Rand, which is one of the reasons why these kinds of package names are often very short
At the other extreme, there are many names and few types of data types like the net/http package, because they have to perform a complex task. Although there are nearly 20 types and more functions, the names of the most important members in the package are simple and clear: Get, Post, Handle, Error, Client and Server