Go是一种令人赞叹的语言,具有很大的发展动力,并且专注于简单性。 这种方法在其标准库中很明显,该库提供了所有基本要素,但不多。
幸运的是,Go拥有一个充满活力的社区,该社区创建并共享了许多第三方库。 在本教程中,我将向您介绍Go的12个最佳软件包和库。 其中一些具有相对狭窄的范围,可以添加到任何项目中,而另一些则是大型项目,您可以将其合并到大规模,大规模的分布式系统中。
太棒了
在深入探究库本身之前,让我向您介绍Awesome Go ,这是一个非常活跃且精心策划的Go库和其他资源列表。 您应该不时访问并检查新功能。
1. Golang-Set
Go具有数组,切片和地图,但是没有固定的数据结构。 您可以使用布尔映射来模拟集合,但最好是具有正确的操作和语义的实际数据类型。 这是golang-set的来源。这是创建新集合,添加项目和测试成员资格的基本示例:
package main
import (
"fmt"
"github.com/deckarep/golang-set"
)
func main() {
basicColors := mapset.NewSet()
basicColors.Add("Red")
basicColors.Add("Blue")
basicColors.Add("Green")
if basicColors.Contains("Green") {
fmt.Println("Yay! 'Green' is a basic color")
} else {
fmt.Println("What a disappointment! 'Green' is not a basic color")
}
if basicColors.Contains("Yellow") {
fmt.Println("Yay! 'Yellow' is a basic color")
} else {
fmt.Println("What a disappointment! 'Yellow' is not a basic color")
}
}
Output:
Yay! 'Green' is a basic color
What a disappointment! 'Yellow' is not a basic color
请注意,程序包名称为“ mapset”。 除了基础知识外,您还执行所有设置操作,例如并集,交集和差。 您还可以遍历设置值:
package main
import (
"fmt"
"github.com/deckarep/golang-set"
)
func main() {
basicColors := mapset.NewSet()
basicColors.Add("Red")
basicColors.Add("Blue")
basicColors.Add("Green")
otherColors := mapset.NewSetFromSlice([]interface{}{"Orange", "Yellow", "Indigo", "Violet"})
rainbowColors := basicColors.Union(otherColors)
for color := range rainbowColors.Iterator().C {
fmt.Println(color)
}
}
2.颜色
让我们继续颜色主题。 在编写命令行程序时,使用颜色突出显示重要消息或区分错误,成功和警告很有用。
颜色包为您的程序添加一些颜色提供了一种简便的方法(请参阅我在那里做的事情?)。 它使用ANSII转义码,也支持Windows! 这是一个简单的示例:
package main
import (
"github.com/fatih/color"
)
func main() {
color.Red("Roses are red")
color.Blue("Violets are blue")
}
颜色包支持将颜色与背景色,粗体或斜体等样式混合,以及将颜色与非颜色输出混合使用。
package main
import (
"github.com/fatih/color"
"fmt"
)
func main() {
minion := color.New(color.FgBlack).Add(color.BgYellow).Add(color.Bold)
minion.Println("Minion says: banana!!!!!!")
m := minion.PrintlnFunc()
m("I want another banana!!!!!")
slantedRed := color.New(color.FgRed, color.BgWhite, color.Italic).SprintFunc()
fmt.Println("I've made a huge", slantedRed("mistake"))
}
彩色包装还有其他有用的功能。 继续探索更多。
3.现在
现在,这是一个非常简单的程序包,它为标准时间程序包提供了方便的包装,并使在当前时间周围轻松处理各种日期和时间构造成为可能。
例如,您可以获取当前分钟的开始时间或最接近当前时间的星期日的结束时间。 这是使用“现在”的方法:
package main
import (
"github.com/jinzhu/now"
"fmt"
)
func main() {
fmt.Println("All the beginnings...")
fmt.Println(now.BeginningOfMinute())
fmt.Println(now.BeginningOfHour())
fmt.Println(now.BeginningOfDay())
fmt.Println(now.BeginningOfWeek())
fmt.Println(now.BeginningOfMonth())
fmt.Println(now.BeginningOfQuarter())
fmt.Println(now.BeginningOfYear())
}
Output:
All the beginnings...
2017-06-04 16:59:00 -0700 PDT
2017-06-04 16:00:00 -0700 PDT
2017-06-04 00:00:00 -0700 PDT
2017-06-04 00:00:00 -0700 PDT
2017-06-01 00:00:00 -0700 PDT
2017-04-01 00:00:00 -0700 PDT
2016-12-31 23:00:00 -0800 PST
您还可以解析时间,甚至添加自己的格式(这将需要更新已知格式)。 Now
类型嵌入了time.Time
,因此您可以直接在Now
对象上使用所有time.Time
方法。
4.根
gen工具会为您生成代码,特别是类型识别代码,它试图缓解Go中没有模板或泛型的空白。
您用特殊注释注释类型,然后gen生成包含在项目中的源文件。 没有运行时魔术。 让我们来看一个例子。 这是带注释的类型。
// +gen slice:"Where,Count,GroupBy[int]"
type Person struct {
Name string
Age int
}
运行gen
(确保它在您的路径中)会生成person_slice.go
:
// Generated by: gen
// TypeWriter: slice
// Directive: +gen on Person
package main
// PersonSlice is a slice of type Person. Use it where you would use []Person.
type PersonSlice []Person
// Where returns a new PersonSlice whose elements return true for func. See: http://clipperhouse.github.io/gen/#Where
func (rcv PersonSlice) Where(fn func(Person) bool) (result PersonSlice) {
for _, v := range rcv {
if fn(v) {
result = append(result, v)
}
}
return result
}
// Count gives the number elements of PersonSlice that return true for the passed func. See: http://clipperhouse.github.io/gen/#Count
func (rcv PersonSlice) Count(fn func(Person) bool) (result int) {
for _, v := range rcv {
if fn(v) {
result++
}
}
return
}
// GroupByInt groups elements into a map keyed by int. See: http://clipperhouse.github.io/gen/#GroupBy
func (rcv PersonSlice) GroupByInt(fn func(Person) int) map[int]PersonSlice {
result := make(map[int]PersonSlice)
for _, v := range rcv {
key := fn(v)
result[key] = append(result[key], v)
}
return result
}
该代码提供了类似于LINQ的方法来对PersonSlice
类型进行操作。 它很容易理解,并且有很好的文档记录。
使用方法如下。 在主要功能中,定义了PersonSlice
。 age()
函数从其Person
参数中选择年龄字段。 生成的GroupByInt()
函数采用age()
函数并从按年龄分组的切片中返回人员(34是吉姆,但23既有简又有凯尔)。
package main
import (
"fmt"
)
// +gen slice:"Where,Count,GroupBy[int]"
type Person struct {
Name string
Age int
}
func age(p Person) int {
return p.Age
}
func main() {
people := PersonSlice {
{"Jim", 34},
{"Jane", 23},
{"Kyle", 23},
}
groupedByAge := people.GroupByInt(age)
fmt.Println(groupedByAge)
}
Output:
map[34:[{Jim 34}] 23:[{Jane 23} {Kyle 23}]]
5. Gorm
Go以其斯巴达性格而闻名。 数据库编程也不例外。 Go最受欢迎的数据库库是相当底层的。 Gorm通过以下功能将对象关系映射世界带到了Go:
- 关联(有一个,有很多,属于,很多对很多,多态)
- 回调(创建/保存/更新/删除/查找之前/之后)
- 预加载(急切加载)
- 交易次数
- 复合主键
- SQL生成器
- 自动迁移
- 记录仪
- 可扩展,基于GORM回调编写插件
但这并不能涵盖所有内容。 如果您来自Python,请不要指望SQLAlchemy魔术。 对于更多花哨的东西,您必须将其降至更低的水平。 这是一个如何将Gorm与sqlite一起使用的示例。 请注意Product结构中的嵌入式gorm.Model
。
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func main() {
db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
panic("failed to connect database")
}
defer db.Close()
// Migrate the schema
db.AutoMigrate(&Product{})
// Create
db.Create(&Product{Code: "L1212", Price: 1000})
// Read
var product Product
db.First(&product, 1) // find product with id 1
db.First(&product, "code = ?", "L1212")
// Update - update product's price to 2000
db.Model(&product).Update("Price", 2000)
// Delete - delete product
db.Delete(&product)
6.鹅
使用关系数据库时,最重要的任务之一就是管理模式。 在某些组织中,修改数据库架构被认为是“小小的”改变。 goose软件包使您可以执行模式更改,甚至在需要时进行数据迁移。 您可以goose up
goose down
走来走去。 不过请注意您的数据,并确保它不会丢失或损坏。
Goose通过对模式进行版本控制并使用与每个模式相对应的迁移文件来工作。 迁移文件可以是SQL命令或Go命令。 这是添加新表的SQL迁移文件的示例:
-- +goose Up
CREATE TABLE person (
id int NOT NULL,
name text,
age int,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE person;
-- +goose up
和-- +goose down
注释告诉goose如何升级或降级架构。
7.滑翔
Glide是Go的软件包管理器。 在单个GOPATH
,您可能有许多具有相互依赖的程序。 解决方案是让每个程序管理其自己的程序包依赖关系供应商目录。 滑行可以帮助完成此任务。
以下是滑行的功能:
- 支持版本控制包,包括语义版本2.0.0支持。
- 支持别名包(例如,使用github forks)。
- 无需修改导入语句。
- 使用所有Go工具。
- 支持Go支持的所有VCS工具(git,bzr,hg,svn)。
- 支持自定义本地和全局插件。
- 存储库缓存和数据缓存可提高性能。
- 平整依赖性,解决版本差异并避免多次包含软件包。
- 按需或在版本控制系统中按需管理和安装依赖项。
依赖项存储在glide.yaml中 ,glide提供了几个命令来管理依赖项:
create, init Initialize a new project, creating a
glide.yaml file
config-wizard, cw Wizard that makes optional suggestions
to improve config in a glide.yaml file.
get Install one or more packages into
`vendor/` and add dependency to
glide.yaml.
remove, rm Remove a package from the glide.yaml
file, and regenerate the lock file.
import Import files from other dependency
management systems.
name Print the name of this project.
novendor, nv List all non-vendor paths in a
directory.
rebuild Rebuild ('go build') the dependencies
install, i Install a project's dependencies
update, up Update a project's dependencies
tree (Deprecated) Tree prints the
dependencies of this project as a tree.
list List prints all dependencies that the
present code references.
info Info prints information about this
project
cache-clear, cc Clears the Glide cache.
about Learn about Glide
mirror Manage mirrors
help, h Shows a list of commands or help for
one command
8.银杏
银杏是一个BDD(行为驱动开发)测试框架。 它使您能够以类似于英语的语法编写测试,并允许较少的技术人员检查测试(及其输出)并验证它们是否符合业务需求。
一些开发人员也喜欢这种风格的测试规范。 它与Go的内置测试包集成在一起,通常与Gomega结合使用。 这是一个银杏+ Gomega测试的例子:
actual, err := foo()
Ω(err).Should(BeNil())
Ω(actual).ShouldNot(BeNil())
Ω(actual.result).Should(Equal(100))
9.等
Etcd是可靠的分布式键值存储。 服务器在Go中实现,而Go客户端通过gRPC与之交互。
它着重于以下方面:
- 简单:定义明确,面向用户的API(gRPC)。
- 安全:具有可选客户端证书身份验证的自动TLS。
- 快速:基准10,000次写入/秒。
- 可靠:使用Raft正确分发。
这是连接到服务器,设置值并获取它的一个示例,包括超时和清除。
func test_get() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: dialTimeout,
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
_, err = cli.Put(context.TODO(), "foo", "bar")
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(),
requestTimeout)
resp, err := cli.Get(ctx, "foo")
cancel()
if err != nil {
log.Fatal(err)
}
for _, ev := range resp.Kvs {
fmt.Printf("%s : %s\n", ev.Key, ev.Value)
}
// Output: foo : bar
}
10. NSQ
NSQ是一个很棒的分布式队列。 我已经成功地将其用作大型分布式系统的主要构建块。 以下是其一些功能:
- 支持无SPOF的分布式拓扑。
- 水平可扩展(没有代理,可以无缝地将更多节点添加到集群)。
- 基于低延迟推送的消息传递(性能)。
- 组合负载平衡和多播样式的消息路由。
- 在流(高吞吐量)和面向工作(低吞吐量)的工作负载下都可以使用Excel。
- 主要在内存中(超出高水位标记的消息透明地保存在磁盘上)。
- 供消费者用来查找生产者的运行时发现服务(nsqlookupd)。
- 传输层安全性(TLS)。
- 数据格式不可知。
- 很少有依赖项(易于部署)和合理,有界的默认配置。
- 支持任何语言的客户端库的简单TCP协议。
- 用于统计信息,管理操作和生产者的HTTP接口(无需发布客户端库)。
- 与statsd集成以进行实时检测。
- 强大的群集管理界面(nsqadmin)。
这是将消息发布到NSQ的方法(避免了错误处理):
package main
import (
"github.com/bitly/go-nsq"
)
func main() {
config := nsq.NewConfig()
p, _ := nsq.NewProducer("127.0.0.1:4150", config)
p.Publish("topic", []byte("message"))
p.Stop()
}
这里是如何消费:
package main
import (
"sync"
"fmt"
"github.com/bitly/go-nsq"
)
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
config := nsq.NewConfig()
q, _ := nsq.NewConsumer("topic", "channel", config)
handler := nsq.HandlerFunc(func(message *nsq.Message) error {
fmt.Printf("Got a message: %v", message)
wg.Done()
return nil
})
q.AddHandler(handler)
q.ConnectToNSQD("127.0.0.1:4150")
wg.Wait()
}
11.码头工人
Docker现在是家喻户晓的名字(如果您的家人大多是DevOps人)。 您可能不知道Docker是在Go中实现的。 您通常不会在代码中使用Docker,但这是一个重要的项目,应该被认为是一个非常成功和流行的Go项目。
12. Kubernetes
Kubernetes是面向云原生应用程序的开源容器编排平台。 这是Go中实现的另一个怪物分布式系统。 我最近写了一本书,叫做《 掌握Kubernetes》 ,其中详细介绍了Kubernetes的最高级方面。 从Go开发人员的角度来看,Kubernetes非常灵活,您可以通过插件对其进行扩展和自定义。
结论
Go是一门很棒的语言。 它的设计理念是成为一种简单易懂的语言。 它的标准库不如Python之类的其他语言那么全面。
Go社区得到了加强,您可以在程序中使用许多高质量的库。 在本文中,我介绍了12个库。 我鼓励您在进入并从头实现所有内容之前,先寻找其他库。
翻译自: https://code.tutsplus.com/tutorials/12-indispensable-go-packages-and-libraries--cms-29008