如何正确的开始用 Go 编程

如何正确的开始用 Go 编程

本文会演示简单的Go软件包的开发过程,并介绍了go命令行工具,这是我们获取,构建和安装Go软件包和命令的标准方法。

go工具要求你以特定方式组织代码。我们会介绍Go安装启动和运行的最简单方法,一定要仔细阅读啊。

组织代码结构

概要

  • Go 程序员一般会将他们的源代码存放在一个工作区中(多个项目放在一个工作区)
  • 工作区中包含许多由 git 管理的代码仓库(也可以是其他版本控制工具管理的)
  • 每个代码仓库包含一个或者多个 Go package
  • 每个 package 由单一目录下的一个或多个Go 源码文件组成
  • package 的目录路径决定了其导入路径

与其他编程语言不同的是,在其他编程语言里每个项目都有自己的工作区,并且工作区都与版本控制系统紧密相关。

工作区

工作区是一个目录层级,这个目录层级在顶层有两个目录:

  1. src 目录,存放源代码文件。
  2. bin 目录,存放可执行二进制文件。

go命令工具会把src中的Go 文件构建生成二进制文件放在bin目录中。

src子目录通常包含用 git 管理的多个代码仓库,他们对应一个或多个Go 包的开发源码。

一个典型的工作区中会包含多个源码仓库,对应多个可执行命令源码和包源码。大多数 Go 程序员会把他们的Go 源码和所有依赖的包都放在单一的工作区中。

下面的例子可以让你更好的了解Go 的工作区大概的样子:

bin/
    hello                          # 可执行命令文件
    outyet                         # 可执行命令文件
src/
    github.com/golang/example/
          .git/                      
          hello/
              hello.go               # 命令文件源码
          outyet/
              main.go                # 命令文件源码
              main_test.go           # 测试文件
          stringutil/
              reverse.go             # package源码
              reverse_test.go        # 测试文件
    golang.org/x/image/
          .git/               
          bmp/
            reader.go              # package 源码
            writer.go              # package 源码
  ......

上面的目录树展示了工作区中的两个代码仓库(example 和 image)。example 仓库中包含两个命令hello 和 outyet(hello 和 outyet 目录中存放的就是两个命令的源码)一个被用作库的 package - stirngutil 。image仓库中包含一个bmp包。

注意:不能使用符号链接(软链 ln -s)将文件链接到工作区中。

执行命令和库是从不同类的源码包构建出来的,这个之后的部分会进行说明。

GOPATH 环境变量

GOPATH环境变量指定工作区的位置。它缺省为用户目录中名为go的目录,因此在Linux上为$HOME/go,在Windows上通常为C:\Users\YourName\Go

如果想在其他位置放置工作区,则需要将GOPATH设置为该目录的路径。请注意,GOPATH不得与GO安装路径相同。

命令go env GOPATH打印当前有效的GOPATH;如果环境变量未设置,它将打印默认位置。为方便起见,可以请将工作区的bin子目录添加到系统环境变量$PATH

$ export PATH=$PATH:$(go env GOPATH)/bin

同时也把GOPATH设置成系统的环境变量:

$ export GOPATH=$(go env GOPATH)

包的导入路径

一个导入路径是用来唯一标识包的字符串,包的导入路径和他在工作区中的位置相对应。标准库中的包具有较短的导入路径,如“fmt”和“net/http”。对于您自己的软件包,你必须选择一个不太可能与将来添加到标准库或其他外部库中的内容冲突的基本路径。

如果你将代码保存在某个源代码库中,那么应该使用该源代码库的根目录作为你的基本路径。例如,如果你在github.com上有一个GitHub帐户user,你创建的仓库都会以 github.com/user 为前缀,那么github.com/user这应该是你的基本路径。

请注意,在构建代码之前,你不需要将代码发布到远程存储库。就像有一天会发布代码一样来组织代码,这是一个好习惯。实际上,您可以选择任意路径名,只要它是唯一的。

我们将使用github.com/user作为基本路径。在工作区内创建一个保存源代码的目录:

$ mkdir -p $GOPATH/src/github.com/user

你的第一个Go程序

要编译并运行一个简单的程序,首先选择一个软件包路径(我们将使用github.com/user/hello),并在您的工作区内创建一个相应的软件包目录:

$ mkdir $GOPATH/src/github.com/user/hello

接下来,在该目录中创建一个名为hello.go的文件,添加以下代码:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world.")
}

现在,你可以使用go工具构建和安装该程序了:

$ go install github.com/user/hello

你可以从系统上的任何位置运行此命令。go命令工具通过在GOPATH指定的工作区内查找github.com/user/hello包来查找源代码。如果从软件包目录运行go Install,可以省略软件包路径:

$ cd $GOPATH/src/github.com/user/hello
$ go install

go install构建hello命令,生成一个可执行的二进制文件。然后,它将该二进制文件作为hello(在Windows下为hello.exe)安装到工作区的bin目录中,hello 可执行命令的位置为 $GOPATH/bin/hello

Go工具仅在发生错误时打印输出,因此如果这些命令没有产生输出,则代表它们已成功执行。

现在,你可以通过在命令行中键入程序的完整路径来运行该程序:

$ $GOPATH/bin/hello
Hello, world.

由于您已将$GOPATH/bin添加到路径中,因此只需键入二进制文件的名字:

$ hello
Hello, world.

你的第一个 library

让我们编写一个库并在上面写的hello程序中使用它。

同样,第一步是选择软件包路径(我们将使用github.com/user/stringutil)并创建软件包目录:

$ mkdir $GOPATH/src/github.com/user/stringutil

接下来在目录中创建reverse.go文件并添加如下代码:

// stringutil包 存放关于字符串的工具函数 
package stringutil

// Reverse 将参数中的字符串反转后的字符串
func Reverse(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}

现在,使用go build测试软件包的编译情况:

$ go build github.com/user/stringutil

go build不会产生输出文件。相反,它将编译后的包保存在本地构建缓存中。

在确认stringutil包构建可以正确之后,修改原始的hello.go(位于$GOPATH/src/github.com/user/hello中)以使用它:

package main

import (
    "fmt"

    "github.com/user/stringutil"
)

func main() {
    fmt.Println(stringutil.Reverse("!oG ,olleH"))
}

再次编译安装 hello 程序后运行他,可以看到输出中的字符串已经被反转了。

$ hello
Hello, Go!

经过上面几步后你的工作区现在应该看起来像下面这样:

bin/
    hello                 
src/
    github.com/user/
        hello/
            hello.go      
        stringutil/
            reverse.go    

包名

go 源码文件中的第一行语句必须是:

package name

其中,name是用于导入的包的默认名称。(包中的所有文件必须使用相同的名称)

go的惯例是包名是导入路径的最后一个元素:作为“crypto/rot13”导入的包它的包名为rot13

生成可执行命令的源码文件必须以 main作为包名。

go 中不要求链接到单个二进制文件的所有包的包名都是唯一的,只要求导入路径(它们的完整文件名)是唯一的。

测试

go有一个由go测试命令和测试包组成的轻量级测试框架。你可以通过创建一个名字以_test.go结尾的文件来编写测试,该文件包含名为TestXXX的函数,签名函数为func(t*testing.T)。测试框架运行每个这样的函数;如果函数调用失败函数,如t.Error或t.Fail,则认为测试失败。

通过创建包含以下go代码的文件$GOPATH/src/github.com/user/stringutil/reverse_test.go,将测试添加到strangutil包。

package stringutil

import "testing"

func TestReverse(t *testing.T) {
    cases := []struct {
        in, want string
    }{
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }
    for _, c := range cases {
        got := Reverse(c.in)
        if got != c.want {
            t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
        }
    }
}

然后使用go test运行测试

$ go test github.com/user/stringutil
ok      github.com/user/stringutil 0.165s

导入路径可以描述如何从版本控制系统(如Git)获取包源代码。Go工具使用此属性自动从远程仓库中获取包。例如,本文档中描述的示例也保存在GitHub 以github.com/golang/example托管的Git存储库中。如果将代码仓库的URL包含在软件包的导入路径中,go将会使用go get`自动获取、构建和安装它:

$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!

如果工作区中没有指定的包,go get将把它放在$GOPATH指定的工作区中。(如果软件包已经存在,go get将跳过远程获取,其行为变得与go install相同。)。

发出上述go get命令后,工作区目录树现在应该如下所示:

bin/
    hello                           
src/
    github.com/golang/example/
        .git/                       
        hello/
            hello.go                
        stringutil/
            reverse.go              
            reverse_test.go         
    github.com/user/
        hello/
            hello.go                
        stringutil/
            reverse.go              
            reverse_test.go         

托管在GitHub上的hello命令依赖于同一仓库中的stringutil包。hello.go文件中的导入使用相同的导入路径约定,因此go get命令也能够定位和安装依赖包。

import "github.com/golang/example/stringutil"

What's Next

WX20191117-152623@2x.png

go语言系统编程,是英文版, What this book covers Chapter 1, Getting started with Go and Unix Systems Programming, starts by defining what systems programming is before talking about the advantages and the disadvantages of Go, the features of Go version 1.8, two handy Go tools named gofmt and godoc, as well as the various states of Unix processes. Chapter 2, Writing Programs in Go, helps you learn how to compile Go code and how to use the environment variables that Go supports, and understand how Go reads the command line arguments of a program. Then, we will talk about getting user input and output, which are fundamental tasks, show you how to define functions in Go, where the defer keyword is mentioned for the first time in this book and continue by discussing the data structures that Go offers using handy code examples. In the remaining sections of the chapter, we will discuss Go interfaces and random number generation. I am sure that you are going to enjoy this chapter! Chapter 3, Advanced Go Features, goes deeper and starts talking about some advanced Go features, including error handling, which is critical when developing systems software and error logging. Then it introduces you to pattern matching and regular expressions, Go Reflection, and talks about unsafe code. After that, it compares Go to other programming languages and presents two utilities, named dtrace(1) and strace(1), that allow you to see what happens behind the scenes when you execute a program. Lastly, it talks about how you can use the go tool to detect unreachable code and how to avoid some common Go mistakes. Chapter 4, Go Packages, Algorithms, and Data Structures, talks about algorithms and sorting in Go and about the sort.Slice() function, which requires Go version 1.8 or newer. Then it shows Go implementations of a linked list, a binary tree and a hash table. After that, it discusses Go packages and teaches you how to create and use your own Go packages. The last part of the chapter discusses Garbage collection in Go. Chapter 5, Files and Directories, is the first chapter of this book that deals with a systems programming topic, which is the handling of files, symbolic links, and directories. In this chapter, you will find Go implementations of the core functionality of Unix tools such as which(1), pwd(1), and find(1), but first you will learn how to use the flag package in order to parse the command-line arguments and options of a Go program. Additionally, you will learn how to delete, rename, and move files as well as how to traverse directory structures the Go way. The last part of this chapter implements a utility that creates a copy of all the directories of a directory structure! Chapter 6, File Input and Output, shows you how to read the contents of a file, how to change them, and how to write your own data to files! In this chapter, you will learn about the io package, the io.Writer and io.Reader interfaces, and the bufio package that is used for buffered input and output. You will also create Go versions of the cp(1), wc(1), and dd(1) utilities. Lastly, you will learn about sparse files, how to create sparse files in Go, how to read and write records from files, and how to lock files in Go. Chapter 7, Working with System Files, teaches you how to deal with Unix system files, which includes writing data to Unix log files, appending data to existing files, and altering the data of text files. In this chapter, you will also learn about the log and log/syslog standard Go packages, about Unix file permissions, and take your pattern matching and regular expressions knowledge even further using practical examples. You will also learn about finding the user ID of a user as well as the Unix groups a user belongs to. Lastly, you will discover how to work with dates and times in Go using the time package and how to create and rotate log files on your own. Chapter 8, Processes and Signals, begins by discussing the handling of Unix signals in Go with the help of the os/signal package by presenting three Go programs. Then it shows a Go program that can rotate its log files using signals and signal handling and another Go program that uses signals to present the progress of a file copy operation. This chapter will also teach you how to plot data in Go and how to implement Unix pipes in Go. Then it will implement the cat(1) utility in Go before briefly presenting the Go code of a Unix socket client. The last section of the chapter quickly discusses how you can program a Unix shell in Go. Chapter 9, Goroutines – Basic Features, discusses a very important Go topic, which is goroutines, by talking about how you can create goroutines and how you can synchronize them and wait for them to finish before ending a program. Then it talks about channels and pipelines, which help goroutines communicate and exchange data in a safe way. The last part of the chapter presents a version of the wc(1) utility that is implemented using goroutines. However, as goroutines is a big subject, the next chapter will continue talking about them. Chapter 10, Goroutines – Advanced Features, talks about more advanced topics related to goroutines and channels, including buffered channels, signal channels, nil channels, channels of channels, timeouts, and the select keyword. Then it discusses issues related to shared memory and mutexes before presenting two more Go versions of the wc(1) utility that use channels and shared memory. Lastly, this chapter will talk about race conditions and the GOMAXPROCS environment variable. Chapter 11, Writing Web Applications in Go, talks about developing web applications and web servers and clients in Go. Additionally, it talks about communicating with MongoDB and MySQL databases using Go code. Then, it illustrates how to use the html/template package, which is part of the Go standard library and allows you to generate HTML output using Go HTML template files. Lastly, it talks about reading and writing JSON data before presenting a utility that reads a number of web pages and returns the number of times a given keyword was found in those web pages. Chapter 12, Network Programming, discusses topics related to TCP/IP and its protocols using the net Go standard package. It shows you how to create TCP and UDP clients and servers, how to perform various types of DNS lookups, and how to use Wireshark to inspect network traffic. Additionally, it talks about developing RPC clients and servers in Go as well as developing a Unix socket server and a Unix socket client. As you will see, at the end of each chapter there are some exercises for you to do in order to gain more information about important Go packages and write your own Go programs. Please, try to do all the exercises of this book
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值