(2023-6-8更新)
资料来源
Go 基础系列 | 骏马金龙
Go 语言教程 | runoob
Go语言学习 | rickiyang | cnblogs
基础知识
环境安装
(Ubuntu22.04 LTS)
sudo apt-get install && apt-get upgrade
sudo apt-get install golang
go version #安装后的版本查询
mkdir ~/workspace
echo 'export GOPATH="$HOME/workspace"' >> ~/.bashrc
source ~/.bashrc
结构
package main
import "fmt"
func main() {
/*注释符号*/
//花括号不能单独放行
fmt.Println("Hello, World!")
}
// 单行注释
go run helloworld.go
- 这个程序的第一行
package main定义了这个文件属于 main 包。在 Go 语言中,每个程序都必须包含一个 main 包,并且在这个包下必须包含一个 main() 函数,作为程序的入口点。 - 第三行
import "fmt"引入了 fmt 包,这个包提供了格式化输入输出的函数。 - 第五行
func main() {定义了程序的入口点 main() 函数。 - 第六行
fmt.Println("Hello, World!")调用了 fmt 包中的 Println() 函数,用于输出一条字符串 "Hello, World!" 到标准输出设备上(通常是控制台)。 - 最后一行
}表示 main() 函数的结束。
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
Go 语言的字符串连接可以通过 + 实现
Go 代码中会使用到的 25 个关键字或保留字:
| break | default | func | interface | select |
|---|---|---|---|---|
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const | fallthrough | if | range | type |
| continue | for | import | return | var |
Go 语言还有 36 个预定义标识符:
| append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
|---|---|---|---|---|---|---|---|---|
| copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
| int32 | int64 | iota | len | make | new | nil | panic | uint64 |
| println | real | recover | string | true | uint | uint8 | uintptr |
程序一般由关键字、常量、变量、运算符、类型和函数组成。
程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。
程序中可能会使用到这些标点符号:.、,、;、: 和 …。
GO语言区分大小写
-
任何需要对外暴露的名字必须以大写字母开头,不需要对外暴露的则应该以小写字母开头。
-
当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Analysize,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);
-
命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )
-
包名应该为小写单词,不要使用下划线或者混合大小写。
文件命名
尽量采取有意义的文件名,简短,有意义,应该为小写单词,使用下划线分隔各个单词。
结构体命名采用驼峰命名法,首字母根据访问控制大写或者小写
struct 申明和初始化格式采用多行
type MainConfig struct {
Port string `json:"port"`
Address string `json:"address"`
}
config := MainConfig{"1234", "123.221.134"}
接口命名
命名规则基本和上面的结构体类型
单个函数的结构名以 “er” 作为后缀,例如 Reader , Writer 。
type Reader interface {
Read(p []byte) (n int, err error)
}
变量命名
和结构体类似,变量名称一般遵循驼峰法,首字母根据访问控制原则大写或者小写,但遇到特有名词时,需要遵循以下规则:
- 如果变量为私有,且特有名词为首个单词,则使用小写,如 appService
- 若变量类型为 bool 类型,则名称应以 Has, Is, Can 或 Allow 开头
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
常量均需使用全部大写字母组成,并使用下划线分词
const APP_URL = "https://www.baidu.com"
如果是枚举类型的常量,需要先创建相应类型:
type Scheme string
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
)
格式化字符串
Go 语言中使用 fmt.Sprintf 或 fmt.Printf 格式化字符串并赋值给新串:
- Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
- Printf 根据格式化参数生成格式化的字符串并写入标准输出。
// 当前程序的包名
package main
// 导入其他包
import . "fmt"
// 常量定义
const PI = 3.14
// 全局变量的声明和赋值
var name = "gopher"
// 一般类型声明
type newType int
// 结构的声明
type gopher struct{}
// 接口的声明
type golang interface{}
// 由main函数作为程序入口点启动
func main() {
Println("Hello World!")
}
错误处理
- 错误处理的原则就是不能丢弃任何有返回err的调用,不要使用 _ 丢弃,必须全部处理。接收到错误,要么返回err,或者使用log记录下来
- 尽早return:一旦有错误发生,马上返回
- 尽量不要使用panic,除非你知道你在做什么
- 错误描述如果是英文必须为小写,不需要标点结尾
- 采用独立的错误流进行处理
// 错误写法
if err != nil {
// error handling
} else {
// normal code
}
// 正确写法
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
常量
在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。在Go程序中,常量可定义为数值、布尔值或字符串等类型。
const PI = 3.14
变量
//定义一个名称为“valName”,类型为"type"的变量
var valName type
//定义三个类型都是“type”的变量
var vname1, vname2, vname3 type
//定义三个类型都是"type"的变量,并且分别初始化为相应的值
//vname1为v1,vname2为v2,vname3为v3
var vname1, vname2, vname3 type= v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3
vname1, vname2, vname3 := v1, v2, v3
/*
:=这个符号直接取代了var和type,这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;
在函数外部使用则会无法编译通过,所以一般用var方式来定义全局变量。
*/
//_(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。在这个例子中,我们将值2赋予b,并同时丢弃1:
_, b := 1, 2
内置数据类型
Go 语言按类别有以下几种数据类型:
布尔型 --> 在Go中,布尔值的类型为bool,值只可以是常量 true 或者 false。一个简单的例子:var b bool = true;
整数型 --> 整型 int 和浮点型 float,Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码;
字符串 --> 字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本;
派生型 -->
(a) 指针类型(Pointer)
(b) 数组类型
(c) 结构化类型(struct)
(d) 联合体类型 (union)
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface)
(h) Map 类型
(i) Channel 类型
//Boolean
var isActive bool // 全局变量声明
var enabled, disabled = true, false // 忽略类型的声明
func test() {
var available bool // 一般声明
valid := false // 简短声明
available = true // 赋值操作
}
| uint8 | 无符号 8 位整型 (0 到 255) |
|---|---|
| uint16 | 无符号 16 位整型 (0 到 65535) |
| uint32 | 无符号 32 位整型 (0 到 4294967295) |
| uint64 | 无符号 64 位整型 (0 到 18446744073709551615) |
| int8 | 有符号 8 位整型 (-128 到 127) |
| int16 | 有符号 16 位整型 (-32768 到 32767) |
| int32 | 有符号 32 位整型 (-2147483648 到 2147483647) |
| int64 | 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
| float32 | IEEE-754 32位浮点型数 |
| float64 | IEEE-754 64位浮点型数 |
| complex64 | 32 位实数和虚数 |
| complex128 | 64 位实数和虚数 |
| byte | 类似 uint8 |
| rune | 类似 int32 |
| uint | 32 或 64 位 |
| int | 与 uint 一样大小 |
| uintptr | 无符号整型,用于存放一个指针 |
iota枚举
这个关键字用来声明enum的时候采用,它默认开始值是0,const中每增加一行加1:
package main
const (
x = iota // x == 0
y
z
w
)
const (
h, i, j = iota, iota, iota //h=0,i=0,j=0 iota在同一行值相同
)
const (
l = iota //a=0
m = "B"
n = iota //2
o, p, q = iota, iota, iota //3,3,3
r = iota //4
)
func main() {
println(x,y,z,w)
println(h,i,j)
println(l,m,n,o,p,q,r)
}
结果:
0 1 2 3
0 0 0
0 B 2 3 3 3 4