介绍
一个包由位于同一目录中的 Go 文件组成,并且在开头具有相同的包语句。您可以从包中包含其他功能,以使您的程序更加复杂。一些包可通过 Go 标准库获得,因此随 Go 安装一起安装。其他的可以用 Go 的 go get 命令安装。您还可以通过使用必要的包语句在要共享代码的同一目录中创建 Go 文件来构建自己的 Go 包。
本教程将指导您编写 Go 包以在其他编程文件中使用。
先决条件
- 按照如何安装和设置 Go 系列的本地编程环境中的教程之一设置 Go 编程环境。按照本地编程环境教程中的第 5 步创建您的 Go 工作区。要遵循本文中的示例和命名约定,请阅读第一部分编写和导入包。
- 要加深您对 GOPATH 的了解,请阅读我们的文章了解 GOPATH。
编写和导入包
编写一个包就像编写任何其他 Go 文件一样。包可以包含函数、类型和变量的定义,然后可以在其他 Go 程序中使用。
在我们创建一个新包之前,我们需要进入我们的 Go 工作区。这通常在我们的 gopath 下。例如,在本教程中,我们将调用包 greet。为此,我们在项目空间下的 gopath 中创建了一个名为 greet 的目录。如果我们的组织是 gopherguides,并且我们想在组织下创建 greet 包,同时使用 Github 作为我们的代码存储库,那么我们的目录将如下所示:
└── $GOPATH
└── src
└── github.com
└── gopherguides
greet 目录位于 gopherguides 目录中:
└── $GOPATH
└── src
└── github.com
└── gopherguides
└── greet
最后,我们可以在我们的目录中添加第一个文件。通常的做法是,包中的主文件或入口点文件以目录名称命名。在这种情况下,我们将在 greet 目录中创建一个名为 greet.go 的文件:
└── $GOPATH
└── src
└── github.com
└── gopherguides
└── greet
└── greet.go
创建文件后,我们可以开始编写我们想要在项目之间重用或共享的代码。在这种情况下,我们将创建一个名为 Hello 的函数来打印 Hello World。
在文本编辑器中打开 greet.go 文件并添加以下代码:
greet.go package greet import "fmt" func Hello() { fmt.Println("Hello, World!") }
让我们分解第一个文件。每个文件的第一行需要您正在使用的包的名称。由于您在 greet 包中,因此您使用 package 关键字,后跟包的名称:
package greet
这将告诉编译器将文件中的所有内容视为 greet 包的一部分。
接下来,您声明需要与 import 语句一起使用的任何其他包。你只在这个文件中使用了一个——fmt 包:
import "fmt"
最后,创建函数 Hello。它将使用 fmt 包打印出 Hello, World!:
func Hello() { fmt.Println("Hello, World!") }
现在您已经编写了 greet 包,您可以在您创建的任何其他包中使用它。让我们创建一个新包,您将在其中使用您的 greet 包。
您将创建一个名为 example 的包,这意味着您需要一个名为 example 的目录。在您的 gopherguides 组织中创建此包,因此目录结构如下所示:
└── $GOPATH └── src └── github.com └── gopherguides └── example 现在您已经有了新包的目录,您可以创建入口点文件。因为这将是一个可执行程序,所以将入口点文件命名为 main.go 被认为是最佳实践: └── $GOPATH └── src └── github.com └── gopherguides └── example └── main.go 在您的文本编辑器中,打开 main.go 并添加以下代码以调用 greet 包:
main.go
package main
import "github.com/gopherguides/greet"
func main() {
greet.Hello()
}
因为您正在导入一个包,所以您需要通过以点表示法引用包名称来调用该函数。点符号是放置句号的做法。在您正在使用的包的名称和您要使用的包中的资源之间。例如,在你的 greet 包中,你有 Hello 函数作为资源。如果要调用该资源,请使用 greet.Hello() 的点表示法。
现在,您可以打开终端并在命令行上运行程序:
go run main.go
完成后,您将收到以下输出:
Output Hello, World!
要了解如何在包中使用变量,让我们在 greet.go 文件中添加一个变量定义:
greet.go
package greet
import "fmt"
var Shark = "Sammy"
func Hello() {
fmt.Println("Hello, World!")
}
接下来,打开您的 main.go 文件并添加以下突出显示的行以在 fmt.Println() 函数中从 greet.go 调用变量:
main.go
package main
import (
"fmt"
"github.com/gopherguides/greet"
)
func main() {
greet.Hello()
fmt.Println(greet.Shark)
}
再次运行程序后:
go run main.go
您将收到以下输出:
Output Hello, World! Sammy
最后,让我们在 greet.go 文件中定义一个类型。您将创建带有名称和颜色字段的 Octopus 类型,以及一个在调用时将打印出字段的函数:
greet.go
package greet import "fmt" var Shark = "Sammy" type Octopus struct { Name string Color string } func (o Octopus) String() string { return fmt.Sprintf("The octopus's name is %q and is the color %s.", o.Name, o.Color) } func Hello() { fmt.Println("Hello, World!") }
打开 main.go 在文件末尾创建该类型的实例:
main.go
package main import ( "fmt" "github.com/gopherguides/greet" ) func main() { greet.Hello() fmt.Println(greet.Shark) oct := greet.Octopus{ Name: "Jesse", Color: "orange", } fmt.Println(oct.String()) }
一旦你用 oct := greet.Octopus 创建了 Octopus 类型的实例,你就可以在 main.go 文件的命名空间中访问该类型的函数和字段。这使您可以在最后一行编写 oct.String() 而无需调用 greet。例如,您还可以调用类型字段之一,例如 oct.Color 而不引用 greet 包的名称。
Octopus 类型的 String 方法使用 fmt.Sprintf 函数创建一个句子,并将结果以字符串形式返回给调用者(在本例中为您的主程序)。
运行程序时,您将收到以下输出:
go run main.go Output Hello, World! Sammy The octopus's name is "Jesse" and is the color orange.
通过在 Octopus 上创建 String 方法,您现在有了一种可重用的方式来打印有关您的自定义类型的信息。如果你想在以后改变这个方法的行为,你只需要编辑这个方法。
导出的代码
您可能已经注意到,您调用的 greet.go 文件中的所有声明都是大写的。 Go 不像其他语言那样具有公共、私有或受保护修饰符的概念。外部可见性由大小写控制。以大写字母开头的类型、变量、函数等在当前包之外是公开可用的。在其包外可见的符号被视为已导出。
如果你向 Octopus 添加一个名为 reset 的新方法,你可以在 greet 包中调用它,但不能从在 greet 包之外的 main.go 文件中调用它:
greet.go
package greet import "fmt" var Shark = "Sammy" type Octopus struct { Name string Color string } func (o Octopus) String() string { return fmt.Sprintf("The octopus's name is %q and is the color %s.", o.Name, o.Color) } func (o *Octopus) reset() { o.Name = "" o.Color = "" } func Hello() { fmt.Println("Hello, World!") }
如果您尝试从 main.go 文件调用 reset:
main.go
package main import ( "fmt" "github.com/gopherguides/greet" ) func main() { greet.Hello() fmt.Println(greet.Shark) oct := greet.Octopus{ Name: "Jesse", Color: "orange", } fmt.Println(oct.String()) oct.reset() }
您将收到以下编译错误:
Output oct.reset undefined (cannot refer to unexported field or method greet.Octopus.reset)
要从 Octopus 导出重置功能,请将重置中的 R 大写:
greet.go
package greet import "fmt" var Shark = "Sammy" type Octopus struct { Name string Color string } func (o Octopus) String() string { return fmt.Sprintf("The octopus's name is %q and is the color %s.", o.Name, o.Color) } func (o *Octopus) Reset() { o.Name = "" o.Color = "" } func Hello() { fmt.Println("Hello, World!") }
因此,您可以从其他包中调用 Reset 而不会出现错误:
main.go
package main import ( "fmt" "github.com/gopherguides/greet" ) func main() { greet.Hello() fmt.Println(greet.Shark) oct := greet.Octopus{ Name: "Jesse", Color: "orange", } fmt.Println(oct.String()) oct.Reset() fmt.Println(oct.String()) }
现在如果你运行程序:
go run main.go
您将收到以下输出:
Output Hello, World! Sammy The octopus's name is "Jesse" and is the color orange The octopus's name is "" and is the color .
通过调用重置,您清除了名称和颜色字段中的所有信息。当您调用 String 方法时,它不会在 Name 和 Color 通常出现的地方打印任何内容,因为这些字段现在是空的。
结论
编写 Go 包与编写任何其他 Go 文件相同,但是将其放在另一个目录中可以隔离代码以在其他地方重用。本教程介绍了如何在包中编写定义,演示了如何在另一个 Go 编程文件中使用这些定义,并解释了将包保存在何处以便访问它的选项。
- 登录 发表评论