大白话go 入门(1)--How to write go code

882 阅读3分钟

每天go一点点,只记录学习中, 自己用到和迷惑的东西, 记录精华部分, 不求大而全.

How to write go code(大白话译文)

How to write go code

网上很多译文, 但是写的都比较模糊, 大多都是直接翻译的, 这里我写上自己的理解, 使用大白话去解读. 英文名词我尽量不翻译. 因为-程序中都是英文.

介绍

这一部分 ①演示如何在一个module里面开发一个package. ②介绍常用的go tool, 它是用来 获取fetch/编译build/安装install modules, packages, commands的.

本文前提: Go 1.13以上版本, GO111MODULE环境变量没有设置.

如何组织代码

package

go程序是以package 包进行组织的, 一个package是指在同一文件夹下的go源文件.go的集合(也就是说, 同一文件夹下的go源文件, 必须同属一个package).

这些同一个文件夹下的go源文件是一起被编译的, 这也就导致任一源文件中定义的 函数/类型/变量/常量 都能直接被同属一个package的其他源文件引用.

repository/module/package的关系

一个repository 仓库可以包含一个/多个module, 一个module是相关的的package的集合. 通常一个repository只包含一个module(处于在repository的根目录, 即: 你会在repository的根目录发现一个go.mod文件).

module path的作用

go.mod文件, 声明了module path, 这个module path是该module下的所有的package的import path的前缀.

那么, 一个module包含哪些package呢? 答案是, go.mod文件的文件夹中的package, 以及该文件夹的子文件中的packages, 都是属于这个module的. (直到遇到一个子文件夹, 它拥有自己的go.mod文件, 此时就是另外一个module了.) 可以理解一个go.mod文件, 声明了一个module

上面说了, module path有一个作用是作为该module下面的packages的import path前缀. 其实它还有别的作用. **module path也指明了go 命令应该去哪里下载这个module. **

举例: 为了下载module path为golang.org/x/tools的module, go命令就会去访问仓库url: https://golang.org/x/tools.

import path

一个module下的package的import path的组成方式是:

module path/subdirectory path to the package

举例:

一个module的module path是 github.com/google/go-cmp, 在go-cmp/cmp/下, 有一个package, 则该packaeg的import path是: github.com/google/go-cmp/cmp.

这里有个例外, 就是标准库中的包, 都没有module path前缀, 如: import fmt.

第一个程序

创建module

首先, 自己想好一个module path, 并创建一个go.mod(创建一个module)

这里我们创建一个文件夹hello/, 在其下面创建一个module, modulepath为: example.com/user/hello

$ mkdir hello 
$ cd hello
$ go mod init example.com/user/hello // module path
go: creating new go.mod: module example.com/user/hello

$ cat go.mod
module example.com/user/hello

为自己的module编写package

go源文件的第一条有效语句, 必须是package name, 可执行的module, 必须有package main.

hello/下, 创建一个hello.go. 代码如下:

package main

import "fmt"

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

此时的目录结构如下:

.
└── hello
    ├── go.mod
    └── hello.go

安装module

由于module包含了package main, 是可执行的, 那我们执行下面的语句, 编译并生成了hello可执行文件(命令).

// go install moduel_path
go install example.com/usr/hello

如果你没有设置$GOBIN, $GOPATH, 则编译生成的hello命令会被默认安装到$HOME/go/bin/hello(windows: %USERPROFILE%\go\bin\hello.exe).

可执行文件(命令)被安装到哪里, 是由$GOBIN > $GOPATH > 默认路径 决定的.

你可以通过如下命令, 设置/取消 go环境变量的设置

go env -w GOBIN=/somewhere/else/bin  // 设置

go env -u GOBIN // 取消

注意:go install module_path命令执行的时候, 必须在相应的module的范围内, 不能在module范围之外的地方通过go install module_path安装相应的module.

如果module path没有在go命令中给出, go命令是可以接收相对路径的(相对当前工作目录), 但是此时go命令的作用对象默认是当前工作目录的package.

如, 在当前的目录下, 以下语句的效果是等价的

// 安装module example.com/usr/hello 
go install example.com/usr/hello 

// 以下两条命令, 安装当前目录下的pacakge hello
go install .  
go install    

repository 和 module path

如果你已经提交你的repository到github, 为了方便别人去使用你的repository, 那么你的仓库的地址和你的module path最好是一致的.

如何引用自己module中的package

在你自己的moudle中, 创建一个新的package

新建一个package morestrings, 为其创建一个目录hello/morestrings/目录结构如下:

.
└── hello
    ├── go.mod
    ├── hello.go
    └── morestrings   //package morestrings所在的文件夹
        └── reverse.go

reverse.go代码如下: 注意函数名是大写开头, 表示可导出的.

package morestrings

// 反转字符串
func ReverseRunes(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去编译package morestrings.

cd hello/morestrings/
go build

这个命令不会有任何输出, 其实它是将编译后的package内容放到了本地的编译缓存中.

引入刚才创建的morestrings包

修改hello.go文件:

package main

import (
	"fmt"
	"example.com/user/hello/morestrings" // package morestrings的import path
)

func main() {
	fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}

安装module hello: go install example.com/usr/hello,

引入远端的module中的包

package的import path描述了如何去获取该pacakge的源代码.

比如: 为了使用 github.com/google/go-cmp/cmp

package main

import (
	"fmt"

	"example.com/user/hello/morestrings"
	"github.com/google/go-cmp/cmp" // 引入外部包
)

func main() {
	fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
	fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}

当你运行go install, go build, go run等命令的时候, go命令会自动的下载你要导入的package所属的module的源代码. 并将该module的版本记录在go.mod文件中.

$ go install example.com/user/hello
go: finding module for package github.com/google/go-cmp/cmp
go: downloading github.com/google/go-cmp v0.4.0
go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.4.0

$ cat go.mod
module example.com/user/hello

go 1.14

require github.com/google/go-cmp v0.4.0
$

依赖的module下载后, 会放到$GOPAHT/pkg/mod/文件夹下. 该module可以被其他的moduel共享使用(版本必须相同).