前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【GO】《GO HANDBOOK》读书笔记

【GO】《GO HANDBOOK》读书笔记

原创
作者头像
阿东
发布2024-03-02 19:34:45
1310
发布2024-03-02 19:34:45
举报
文章被收录于专栏:公众号:懒时小窝

#Go

引言

非常入门的一本书?准确来说是一篇GO的入门文章,用于学学英语和简单了解GO还不错,并且词汇和语法都比较简洁易懂。

话不多说,下面就来看看这篇文章的翻译。

原文

https://www.freecodecamp.org/news/go-beginners-handbook/

1.介绍GO

它是由谷歌工程师创建的,设计这门语言的主要目标是:

  • 提高项目的编译和运行速度
  • 入门门槛足够低,但是也要避免过于简单和低级。
  • 具备可移植(编译后的 Go 程序是二进制文件,不需要其他文件就能运行,而且是跨平台的,因此可以很容易地分发)
  • 单调、稳定、可预测,犯错的机会少 。
  • 能充分发挥多线程优势

2.如何开始?

在深入了解该语言的具体内容之前,您应该了解以下几件事。

首先,https://go.dev 是该语言的主页。

下面是首选的入门资源:

3.安装 GO

安装GO的教程网上一抓一大把,个人这里演示Window环境,Windows 环境下只需要安装exe应用程序即可。

4.开发 IDE 安装和配置

NOTE: you might have to open a new terminal before you can run the program, as the installer added the Go binaries folder to the path.注意:由于安装程序在路径中添加了 Go 二进制文件夹,运行程序前可能需要打开一个新的终端。

在使用IDE之前,请先确保自己的环境变量可以正常使用GO。

本书使用的是 VS Code,具体可以阅读此网站了解:Go with Visual Studio Code

[【Go】Go in Visual Studio Code]

VS Code安装之后,需要安装GO相关的扩展:marketplace.visualstudio.com/items?itemName=golang.go

5.你好,世界

  1. 创建一个新的文件夹,比如下面的 hello。
  1. 创建一个hello.go的文件,并且在文件内写入下面的内容:
代码语言:go
复制
package main 

import "fmt" 

func main() { 
	fmt.Println(" Hello, World!") 
}
  1. 在文件所在路径,运行go run hello.go,如果结果如下说明运行成功:
代码语言:go
复制
xander@LAPTOP-47J243NL MINGW64 /e/adongstack/go/hello

$ go run hello.go
 Hello, World!

下面来解释下上面的入门程序:

  1. 每个 .go 文件首先声明它是哪个软件包的一部分
  2. 一个软件包可以由多个文件组成,也可以只由一个文件组成。一个程序可以包含多个软件包。
  3. main函数是程序的入口点,也是可执行程序的标识。
  4. 我们使用 import 关键字来导入程序包。

fmt is a built-in package provided by Go that provides input/ output utility functions.fmt 是 Go 提供的一个内置包,提供输入/输出实用功能。

GO官方拥有庞大的标准库,从网络连接到数学、密码、图像处理、文件系统访问等,我们都可以使用它。

Standard library - Go Packages

比如,有关fmt 这个包的文档介绍可以查看这个地址了解:fmt package - fmt - Go Packages,根据文档,该函数功能是 "根据格式说明符进行格式化,并写入标准输出"。

我们使用 "点 "语法 fmt.Println()来指定该函数由该程序包提供。

当代码执行完主函数后,就没有其他事情可做了,执行结束。

在main函数中,我们定义了fmt.Println(" Hello, World!")这样一串代码。

6.编译并运行 Go 程序

本部分接着上一章节的入门程序介绍,解释如何编译并且运行go程序

代码语言:go
复制
go run hello.go

go run 工具首先编译,然后运行指定的程序。

我们可以使用 go build 创建二进制文件:

代码语言:go
复制
go build hello.go

个人电脑上执行的结果如下:

代码语言:sh
复制
PS E:\adongstack\go\hello> go build .\hello.go
PS E:\adongstack\go\hello> dir


    目录: E:\adongstack\go\hello


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2023/9/19     13:33        1897472 hello.exe
-a----         2023/9/19     13:32             84 hello.go

Go 是可移植的,因为本质编译之后本质就是二进制文件,这样每个人都可以按原样运行程序,并且二进制文件已经打包供执行。程序将在我们构建它的相同架构上运行。

我们可以使用 GOOSGOARCH 环境变量为不同的架构创建不同的二进制文件:

代码语言:go
复制
GOOS = windows GOARCH = amd64 go build hello.go

这将为 64 位 Windows 机器创建一个 hello.exe 可执行文件:

image.png
image.png

64 位 macOS(英特尔或苹果)的设置为

代码语言:go
复制
GOOS = darwin GOARCH = amd64

Linux 为 :

代码语言:go
复制
GOOS = linux GOARCH = amd64

这是 Go 的最佳功能之一。

7.工作空间

Go有一个特别之处就是我们所说的工作空间。

工作区是 Go 的 "大本营"。

默认情况下,Go 会选择 $ HOME/ go路径,因此你会在主目录中看到一个 go 文件夹。

例如,当我在 VS Code 中加载 hello.go 文件时,它提示我安装 gopls 命令、Delve 调试器 (dlv) 和 staticcheck linter。

它们已自动安装在 $ HOME/ go 下:

当你使用 go install 安装软件包时,它们将被存储在这里。这就是我们所说的 GOPATH。

你可以更改 GOPATH 环境变量来改变 Go 安装包的位置。

当你同时在不同的项目中工作,并希望隔离你使用的库时,这一点非常有用。

8.深入语言

既然我们已经有了初步的概念,并运行了第一个 Hello, World! 程序,那么我们就可以深入研究这门语言了。

这种语言没有语义上重要的空白。

就像 C、C + +、Rust、Java 和 JavaScript。与 Python 不同的是,Python 的空白是有意义的,它被用来创建块而不是大括号。

Go 非常重视缩进和视觉顺序。安装 Go 时,我们还可以使用 gofmt 命令行工具来格式化 Go 程序。

VS Code 在引擎盖下使用该工具来格式化 Go 源文件。

这是一个非常有意思的特性,语言创建者定义了规则,每个人都会使用这些规则。

这非常适合大型团队的项目。

本书建议在VS Code 当中设置 “Format on Save” 以及 “Format on Paste”:

Go 中的注释使用常见的 C / C + + / JavaScript / Java 语法:

9.变量

在 GO 里面可以是用 var关键字定义变量:

代码语言:go
复制
var age = 20

var 关键字可以定义包级别变量:

代码语言:go
复制
package main 

import "fmt" 

var age = 20 

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

或者定义在函数内部:

代码语言:go
复制
package main 

import "fmt" 



func main() { 

	var age = 20 
	
	fmt.Println(" Hello, World!") 
}

在软件包级别定义的变量在组成软件包的所有文件中都是可见的。

一个软件包可以由多个文件组成,只需创建另一个文件,并在顶部使用相同的软件包名称即可。

在函数内部定义的变量,一个变量只能在函数中可见。

这使得 Go 判断变量 age 的类型是 int。

我们稍后会看到更多关于类型的内容,但你应该知道有许多不同的类型,首先是 int、string 和 bool。

我们也可以声明一个没有现存值的变量,但在这种情况下,我们必须像这样设置类型:

代码语言:go
复制
var age int 
var name string 
var done bool

当您知道变量值时,通常使用带有:= 操作符的短变量声明:

代码语言:go
复制
age := 10 
name := "Roger"

注意变量名称是区分大小写的,如果名称较长,通常使用驼峰字母大写,因此我们使用 carName 来表示汽车的名称。

您可以使用赋值运算符 = 为变量赋值。

代码语言:go
复制
var age int 
age = 10 
age = 11

如果一个变量确定不会改变,可以使用const关键字定义:

代码语言:go
复制
const age = 10

你可以在一行定义多个变量:

代码语言:go
复制
var age, name = 10, "Roger" 

// or 

age, name := 10, "Roger"

如果定义了变量但是没有使用,在VS Code 中会有相关提示。

这些错误信息实际是编译

如果您声明一个变量,但没有将其初始化为一个值,那么它会自动分配一个值,这个值取决于变量的类型,例如整数为 0,字符串为空字符串。

10.基本类型

Go 的基本类型有

  • 整数(int、int8、int16、int32、rune、int64、uint、uintptr、uint8、uint16、uint64)
  • 浮点数(float32、float64),用于表示小数
  • 复数类型(complex64、complex128),用于数学运算
  • 字节(byte),表示单个 ASCII 字符
  • 字符串(string),一组字节
  • 布尔类型(bool),表示真或假

我们有很多不同的类型来表示interger,大部分时间你都会使用int,你可能会选择一个更专业的类型来进行优化(刚开始学习时不需要考虑这些)。

int 类型针对 32位机器和64位的机器做了类型适配,

uint 是一个无符号的 int,如果知道数值不会是负数,就可以用它来加倍存储数值。

11.字符串

Strings 在 Go 语言中是一串字节数组。

我们可以使用下面的语法定义一串字符串:

代码语言:go
复制
var name = "test"

值得注意的是,与其他语言不同,字符串的定义只能使用双引号,而不能使用单引号(比如 JS)。

可以使用len 函数获取字符串长度

代码语言:go
复制
len( name) // 4

您可以使用方括号访问单个字符,同时传递您要获取的字符的索引:

代码语言:go
复制
name[ 0] //" t" (indexes start at 0) 
name[ 1] //" e"

可以使用下面的语法像Python语言一样对于字符串进行“切片”:

代码语言:go
复制
name[ 0: 2] //" te" 
name[: 2] //" te" 
name[ 2:] //" st"

使用下面的语法可以拷贝一个字符串:

代码语言:go
复制
var newstring = name[:]

您可以将一个字符串赋值给一个新变量:

代码语言:go
复制
var first = "test" 
var second = first

Strings 是不可变变量,意味着你不能更新一个Strings,即使使用赋值运算符为第一项赋值,第二项的值仍然是 "test":

代码语言:go
复制
var first = "test" 

var second = first 

first = "another test" 

first //" another test" 
second //" test"

字符串是引用类型,这意味着如果将字符串传递给函数,复制的将是字符串的引用,而不是其值。

但由于字符串是不可变的,在这种情况下,与传递 int 等类型的字符串在实际操作中并无太大区别。

可以使用 + 运算符连接两个字符串:

代码语言:go
复制
var first = "first" 

var second = "second" 

var word = first + " " + second //" first second"

Go 在字符串包中提供了多个字符串实用程序。

我们已经在 "Hello, World!"示例中看到了如何导入包,下面介绍如何导入字符串:

以下是导入字符串的方法:

代码语言:go
复制
package main 

import ( "strings" )

12.数组

数组是由单一类型的项目组成的序列。

我们这样定义一个数组:

代码语言:go
复制
var myArray [3] string // 包含 3 个字符串的数组

你可以使用以下值初始化数组:

代码语言:go
复制
var myArray = [3] string{" First", "Second", "Third"}

在这种情况下,你也可以让 Go 来帮你计数:

代码语言:go
复制
var myArray = [...] string{" First", "Second", "Third"} 

注意,数组只能包含相同类型的值。

数组不能调整大小,必须在 Go 中明确定义数组的长度。

数组不能调整大小,必须在 Go 中明确定义数组的长度。

这是数组类型的一部分。此外,也不能使用变量来设置数组的长度。

由于这种限制,在 Go 中很少直接使用数组,而是使用 Slice(稍后会详细介绍)。

注意 Slice 底层也是数组实现的,所以了解数组是基础。

数组可以通过方括号加下标值获取数组特定位置,然后针对特定位置设置新值。

代码语言:go
复制
myArray[ 0] // indexes start at 0 

myArray[ 1]

数组也可以使用len() 函数获取数组长度:

数组是值类型。这意味着可以复制数组:

代码语言:go
复制
anotherArray := myArray

将数组传递给函数,或从函数中返回数组,都会创建原始数组的副本

这与其他编程语言不同。

让我们举一个简单的例子,在复制一个数组项后,给它赋一个新值。

请看,拷贝并没有改变:

代码语言:go
复制
var myArray = [3] string{" First", "Second", "Third"} 

myArrayCopy := myArray 

myArray[ 2] = "Another" 

myArray[ 2] //" Another"
myArrayCopy[ 2] //" Third"

请记住,你只能在数组中添加单一类型的项,因此设置 myArray[ 2] = 2 会引发错误。

底层元素在内存中连续存储。

低级元素持续存储在内存中。

13.分片

分片是一种类似于数组的数据结构,但它的大小可以改变。

切片使用数组,是建立在数组之上的一种抽象结构,它使切片更灵活、更有用(将数组视为低级结构)。

如果你知道需要对切片执行操作,你可以要求它拥有比最初需要的更大容量,这样当你需要更多空间时,空间就会随时可用(而不是找到切片并将其移动到一个有更多空间的新内存位置,然后通过垃圾回收处理旧位置)。

我们可以为 make() 添加第三个参数来指定容量:

代码语言:go
复制
newSlice := make([] string, 0, 10) // an empty slice with capacity 10

多个切片可以使用同一个数组作为底层数组:

代码语言:go
复制
myArray := [3] string{" First", "Second", "Third"} mySlice = myArray[:]

与字符串一样,使用该语法可以获取片段的一部分:

代码语言:go
复制
mySlice := [] string{" First", "Second", "Third"} newSlice := mySlice[: 2] // get the first 2 items newSlice2 := mySlice[ 2:] // ignore the first 2 items newSlice3 := mySlice[ 1: 3] // new slice with items in position 1-2

14.Maps

map 是go语言的常用数据类型。

代码语言:go
复制
agesMap := make( map[ string] int)

您无需设置地图可容纳的物品数量。您可以通过这种方式向map添加新内容:

代码语言:go
复制
agesMap[" flavio"] = 39

您也可以使用以下语法直接用值初始化映射:

代码语言:go
复制
agesMap := map[ string] int{" flavio": 39}

通过下面的语法可以获取map的key的值:

代码语言:go
复制
age := agesMap[" flavio"]

使用delete() 函数可以删除Map中对应的Key。

代码语言:go
复制
delete( agesMap, "flavio")

15.循环

Go 的循环语句关键字也是for:

代码语言:go
复制
for i := 0; i < 10; i + + { 

	fmt.Println( i) 
}

我们首先初始化一个循环变量,然后设置每次迭代时要检查的条件,以决定循环是否应该结束,最后在每次迭代结束时执行 post 语句,在本例中,该语句会递增 i。

i++ 使 i 变量递增。

< 操作符用于将 i 与数字 10 进行比较,并返回 true 或 false,以决定是否执行循环体。

与 C 或 JavaScript 等其他语言不同,我们不需要在该代码块周围使用括号。

此外还需要注意,Go 没有 while这样的循环语法,如果想要实现类似的功能,可以使用for进行模拟。

代码语言:go
复制
i := 0 for i < 10 { 

	fmt.Println( i) i + + 
	
}

此外可以通过break语句跳出循环。

代码语言:go
复制
for { 
	fmt.Println( i) 
	 
	 if i < 10 { 
		 break 
	 } 
	 i ++ 
}

我在循环体中使用了 if 语句,但我们还没有看到条件!我们下一步再做。

现在我要介绍的是范围。

我们可以使用 for 语法遍历数组:

代码语言:go
复制
numbers := [] int{ 1, 2, 3} 

for i, num := range numbers { 
	fmt.Printf("% d: %d\ n", i, num) 
} 

// 0: 1 

// 1: 2 

// 2: 3

注:我使用了 fmt.Printf(),它允许我们使用表示十进制整数的 %d 和表示添加行结束符的 \n 来向终端打印任何值。

当不需要使用index时,使用这种语法很常见:

代码语言:go
复制
for _, num := range numbers { 
	//... 
}

使用表示 "忽略这个 "的特殊 _ 字符,以避免 Go 编译器出现 "你没有使用 i 变量!"的错误。

16.条件式

条件语句的语法和其他语言类似:

代码语言:go
复制
if age < 12 { // child 
} else if age < 18 { 
// teen 

} else { 

// adult 

}

和其他语言一样,在if或者else代码块中定义变量,变量的可见范围等同于代码块的范围。

如果要使用多个不同的 if 语句来检查一个条件,最好使用 switch

代码语言:go
复制
switch age 
{ 
case 0: fmt.Println(" Zero years old") 
case 1: fmt.Println(" One year old") 
case 2: fmt.Println(" Two years old") 
case 3: fmt.Println(" Three years old") 
case 4: fmt.Println(" Four years old") 
default: fmt.Println( i + " years old") 
}

与 C、JavaScript 和其他语言相比,您不需要在每种情况后都有一个分隔符。

17.操作符

到目前为止,我们在代码示例中使用了一些运算符,如 =、:= 和 <。

我们使用赋值运算符 = 和 := 来声明和初始化变量:

代码语言:go
复制
var a = 1 

b := 1

我们有比较运算符 == 和 != ,它们接受 2 个参数并返回布尔值。

代码语言:go
复制
var num = 1 

num == 1 // true 
num != 1 // false

当然还有下面的内容:

代码语言:go
复制
var num = 1 

num > 1 // false 
num >= 1 // true 
num < 1 // false 
num <= 1 // true

我们有二进制(需要两个参数)算术运算符,如 + - * / %

代码语言:go
复制
1 + 1 // 2 
1 - 1 // 0 
1 * 2 // 2 
2 / 2 // 1 
2 % 2 // 0

+ 运算符可以连接字符串:

代码语言:go
复制
"a" + "b" //" ab"

我们有一元运算符 ++-- 来递增或递减数字:

代码语言:go
复制
var num = 1 
num++ // num == 2 
num-- // num == 1

请注意,与 C 或 JavaScript 不同的是,我们不能像 ++num 那样将它们前置到数字上。

此外,该操作不会返回任何值。

我们有布尔运算符帮助我们根据真假值做出决定:&&||!

代码语言:go
复制
true && true // true 
true && false // false 
true || false // true 
false || false // false 
!true // false 
!false // true

18.结构

结构体是一种包含一个或多个变量的类型。它就像是变量的集合。我们称之为字段。它们可以有不同的类型。

下面是定义结构体的代码:

代码语言:go
复制
type Person struct { 
	Name string 
	Age int 
}

请注意,我使用了大写字母作为字段名称,否则这些字段将成为软件包的私有字段,当您将结构体传递给另一个软件包提供的函数(如我们用于处理 JSON 或数据库的函数)时,就无法访问这些字段。

定义结构体后,我们就可以用该类型初始化变量:

代码语言:go
复制
flavio := Person{" Flavio", 39}

可以使用下面的方式获取结构体的字段数据:

代码语言:go
复制
flavio.Age // 39 

flavio.Name //" Flavio"

结构体非常有用,因为它可以将不相关的数据分组,并将其传递给函数或从函数中传递出来,还可以存储在片段中,等等。

一旦定义,结构体就是一种类似 int 或字符串的类型,这意味着你也可以在其他结构体内部使用它:

代码语言:go
复制
type FullName struct { 

FirstName string 
LastName string 

} 

type Person struct { 

Name FullName 
Age int 

}

19.Functions

函数是一个代码块,它被赋予一个名称,并包含一些指令。

在 "你好,世界!"示例中,我们创建了一个 main 函数,它是程序的入口。

代码语言:go
复制
package main import "fmt" func main() { fmt.Println(" Hello, World!") }

通常,我们用自定义名称定义函数:

代码语言:go
复制
func doSomething() { 

然后通过下面的方式调用函数:

代码语言:go
复制
doSomething()

函数可以接受参数,我们必须这样设置参数的类型:

代码语言:go
复制
func doSomething( a int, b int) { 

} 

doSomething( 1, 2)

a 和 b 是函数内部参数的名称。

函数可以返回一个值,就像下面这样:

代码语言:go
复制
func sumTwoNumbers( a int, b int) int {

	return a + b 

} 

result := sumTwoNumbers( 1, 2)

请注意,这里指定了返回值类型

GO 语言的return 可以返回超过一个值:

代码语言:go
复制
func performOperations( a int, b int) (int, int) { 
	return a + b, a - b 
} 

sum, diff := performOperations( 1, 2)

这很有趣,因为许多语言只允许一个返回值。函数内部定义的任何变量都是函数的局部变量。

函数也可以接受数量不限的参数,在这种情况下,我们称之为变量函数:

代码语言:go
复制
func sumNumbers( numbers ... int) int { 
	sum := 0 
	for _, number := range numbers 
	{ 
		sum + = number 
	} 
	return sum 
} 

total := sumNumbers( 1, 2, 3, 4)

20.指针

GO语言支持使用指针,假设使用下面的变量定义:

代码语言:go
复制
age := 20

有了变量指针后,就可以使用 * 运算符获取其指向的值:

代码语言:go
复制
age := 20 
ageptr = &age 
agevalue = *ageptr

这在调用函数并将变量作为参数传递时非常有用。

Go 默认将变量值复制到函数内部,因此不会改变 age 的值:

代码语言:go
复制
func increment(a int) { 

	a = a + 1 
					  
} 

func main() { 
	age := 20 
	increment(age) // age is still 20 
	
}

为此,您可以使用指针:

代码语言:go
复制
func increment( a *int) { 
	
	*a = *a + 1
	
} 

func main() { 

age := 20 
			 
 increment(& age) // age is now 21 
 
 }

21.函数

一个函数可以分配给一个结构体,在这种情况下,我们称之为方法。

代码语言:go
复制
type Person struct { 

	Name string Age int 
	
} 

func (p Person) Speak() { 

	fmt.Println(" Hello from " + p.Name) 
	
} 


func main() { 

	flavio := Person{ 
		Age: 39, 
		Name: "Flavio"
	} 
	
	flavio.Speak() 

}

方法参数可以指定指针类型或者值类型,这将是一个指针接收器,用于接收指向结构实例的指针:

代码语言:go
复制
func (p *Person) Speak() { fmt.Println(" Hello from " + p.Name) }

22.接口

接口是一种定义了一个或多个方法签名的类型。方法没有实现,只有签名:名称、参数类型和返回值类型。类似于这样:

代码语言:go
复制
type Speaker interface { Speak() }

现在,你可以让函数接受任何类型,并实现接口定义的所有方法:

代码语言:go
复制
func SaySomething( s Speaker) { 
	s.Speak() 
}

我们可以将实现这些方法的任何结构传递给它:

代码语言:go
复制
type Speaker interface { 
	Speak() 
	
} 

type Person struct { 
	Name string Age int 
} 

func (p Person) Speak() { 
	fmt.Println(" Hello from " + p.Name) 
} 

func SaySomething( s Speaker) { 
	s.Speak() 
}

func main() { 

	flavio := Person{ Age: 39, Name: "Flavio"} 
	SaySomething( flavio) 
}

23. 下一步行动

本手册介绍 Go 编程语言。除了这些基础知识,现在还有很多东西需要学习。

垃圾回收、错误处理、并发和网络、文件系统 API 等等。学习无止境。

我的建议是,选择一个你想构建的程序,然后开始学习你需要的东西。这会很有趣,也很有收获。

相关

【Linux】《The Command Line Handbook》 读书笔记(上半部分)

【Linux】《The Command Line Handbook》 读书笔记(下半部分)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 原文
  • 1.介绍GO
  • 2.如何开始?
  • 3.安装 GO
  • 4.开发 IDE 安装和配置
  • 5.你好,世界
  • 6.编译并运行 Go 程序
  • 7.工作空间
  • 8.深入语言
  • 9.变量
  • 10.基本类型
  • 11.字符串
  • 12.数组
  • 13.分片
  • 14.Maps
  • 15.循环
  • 16.条件式
  • 17.操作符
  • 18.结构
  • 19.Functions
  • 20.指针
  • 21.函数
  • 22.接口
  • 23. 下一步行动
  • 相关
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档