这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
Let's go to "Go"
本文分为两部分:Go语言简介,Go语言开发入门
其中Go语言开发入门分开开发环境配置和基础语法,基础语法部分指出了 Go 语言语法的独特之处和要点,适合有一定编程语言基础的小伙伴们阅读,如需学习详细语法请阅读 Go语言圣经 等专业书籍
1.Go 语言简介
1.1 你好,Gopher
记得这只蓝皮土拨鼠嘛,它便是 Go 的吉祥物:Gopher。
Gopher 由 Renee 创造,它代表 Go 项目和世界各地的 Go 程序员,并且是 Go 世界中最流行的东西之一。
那么这只憨态可掬的土拨鼠能为程序员做些什么呢?
1.2 Go 是一门什么样的语言
Build fast, reliable, and efficient software at scale
- Go is an open source programming language supported by Google
- Easy to learn and get started with
- Built-in concurrency and a robust standard library
- Growing ecosystem of partners, communities, and tools
Go 语言具有以下特点
- 高性能、高并发
- 语法简单、学习曲线平缓
- 丰富的标准库
- 完善的工具链
- 静态编译
- 跨平台
- 垃圾回收
当前 Go 被广泛用于高并发场景
2.Go 语言开发入门
2.1 开发环境配置
我的电脑为 archlinux 系统, 所以直接使用 pacman 即可轻松完成环境安装与配置 如果小伙伴可以到官网上学习响应的安装配置教程
Go 语言官网:golang.google.cn/
GoLand 官网:www.jetbrains.com/go/promo/
1.更新系统
$ sudo pacman -Syu
2.安装 Go
$ sudo pacman -S go
3.验证 Go 是否安装成功
$ go version
> go version go1.18.1 linux/amd64
4.安装 Goland
$ sudo pacman -S goland
5.拉取项目
在开始界面点击 Get from VCS ,填入青训营给的练习仓库即可完成项目的 clone
6.验证开发环境
找到项目下的 go-by-example/example/01-hello/main.go 文件,其中代码如下面所示,没错就是经典的 "hello world",运行它吧!
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
2.2 基础语法
由于本人已有一定编程基础,这里只重点记录了 Go 语言的独特之处,这部分内容主要摘自 Go语言圣经 《The Go Programming Language》,有需要的小伙伴们可以去看看
入门
我们还是以 helloword 为例来入门
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
- Go 是一门编译型语言,Go 语言的工具链将源代码及其依赖转换成计算机的指令。在终端中输入 go, 即可获得相关命令信息
例如,我们可以使用 run 来编译和运行我们编写的 helloworld 程序
$ go run helloworld.go
> hello world
- Go 语言原生支持 Unicode,它可以处理全世界任何语言的文本
- Go 语言的代码通过 package 组织,标明该文件属于哪个包
- Go 语言通过 import 导入包,且必须跟在 package 后
- Go 一个函数的声明由 func 关键字、函数名、参数列表、返回值列表以及大括号
- Go 语言在代码格式上采取了很强的态度,gofmt 工具把代码格式化为标准格式
程序结构
命名风格:尽量短小、驼峰式命名
声明
-
var、const、type、func 分别对应变量、常量、类型和函数实体对象的声明
-
变量类型后置
-
简短变量声明 a:=1,广泛应用
- 简短变量声明左边的变量可能并全都是刚刚声明的,如果已经声明过则为赋值行为
- 简短变量声明语句中必须至少要声明一个新变量
- 一个指针对应变量在内存中的存储位置,任何类型的指针的零值都是 nil
-
表达式 new(T) 将创建一个 T 类型的匿名变量,初始化为 T 类型的零值,然后返回变量地址,返回的指针类型 *T,好处是不用专门声明一个临时变量
赋值
- a = b 即可完成赋值
- 元组赋值允许同时更新多个变量的值,先对右表达式求值,然后统一更新变量的值
- 隐式赋值:函数调用、返回语句、符合字面量都有可能产生隐式赋值
类型
- type 类型名 底层类型 是一个类型声明语句
- 新命名的类型提供了一个方法,来分隔不同概念的类型,即使底层类型相同也不兼容
- 类型声明语句一般出现在包一级,因此如果新创建的类型名字的首字符大写,则在外部包也可以使用
包和文件
- 包和其他语言模块和库概念类似,目的是为了支持模块化、封装、单独编译和代码重用
- 每个包都对应一个独立的名字空间
- import 通过全局唯一的导入路径导入包
- 包的初始化首先解决包级变量的依赖顺序,然后按照包级变量声明出现的顺序依次初始化,排序的工作交给 Go 语言的构建工具来做
作用域: 区分作用域与生命周期
- 声明语句的作用域对应源代码的一个文本区域,是编译时的属性
- 声明周期是指程序运行时变量存在的有效时间段,是运行时的概念
基础数据类型
Go 语言主要有 4 种数据类型:基础类型、复合类型、引用类型、接口类型
基础类型我们主要关注一下几个性质
- 布尔型并不会隐式转化为数字 0 或 1,必须用一个显式的 if 语句辅助转化
- 一个字符串是一个不可改变的字节序列,不可修改
- 常量表达式在编译期计算,而不是运行期。每种常量的潜在类型都是基础类型
复合数据类型
数组
- 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成
Slice
- Slice 代表变长的序列,序列每个元素都有相同的元素,可以看成没有固定长度的数组
- Slice 比较不能用 ==,除了[]byte 类型的 Slice 有 bytes.Equal 函数支持外,其他类型需要自己展开每个元素比较
- Slice的元素是间接引用,一个固定的Slice在不同的时间可能包含不同的元素值,因为底层的数组元素可能会被修改
- 必须把 append 结果赋值回原数组, slice 原理:长度+容量+指向数组的指针,容量不够会扩容返回新slice
Map
- Map 是一个哈希表的引用 map[K]V, 无序的 key/value对的集合
- Map 的迭代顺序是不确定的,并且不同的含义函数实现可能导致不同的遍历顺序,每一次的遍历顺序都不同
结构体
- 结构体不能包含同类型的成员,但是可以包含其指针类型,可以借此实现递归结构
- 结构体面值两种形式
type user struct {
name string
password string
}
//以成员名字和值来初始化,顺序不重要,如果不出现默认零值
a := user{name: "wang", password: "1024"}
//要求以结构体成员定义顺序为每个成员指定一个面值
b := user{"wang", "1024"}
- 如果结构体全部成员都可以比较,则可以使用 ==
- 结构体嵌入和匿名成员,我们可以直接访问叶子属性而不需要给出完整的路径
JSON
type userInfo struct {
Name string //首字母大写
Age int `json:"age"` //默认输出大写,加个 tag, 可以把输出的字段名改成小写
Hobby []string
}
- 编组:使用json.Marshal 函数将 Go 数据类型转为 JSON
- 默认使用 Go 语言结构体成员名字作为 JSON 的对象
- 选择用大写字母开头的成员名称
- 解码:使用json.Unmarshal 函数将 JSON 转为 Go 数据类型
函数
- 函数声明包括函数名、形参列表、返回值列表(可甚略)、函数体
- 函数可以有多个返回值,一般返回两个值,第一个为期望的返回值,第二个为出错时的错误信息
- Go 语言中函数和其他值一样永远类型,可以赋值给其他变量,可以作为参数传递,可以被返回
- 函数的零值为 nil
- 在调用普通函数或方法前加上关键字 defer,则当 defer语句被执行时,跟在 defer 后面的函数会被延迟执行,知道包含该 defer 语句的函数执行完毕时,defer后的函数才会被执行。
- 可以在一个函数中执行多条 defer 语句,它们的执行顺序与声明顺序相反,多用于处理成对的操作
- 释放资源的 defer 应该直接跟在请求资源语句后面
方法
- 在函数声明时,在其名字之前放下一个变量,就是一个方法。这个附加的参数会将该函数附加到这种类型上,相当于为这种类型定义的独占的方法。可以类比其他语言的类成员函数
type Point struct{X, Y float64}
// 函数
func Distance(p, q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
//方法
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
引用参考
Go 官网:golang.google.cn/
Go 语言圣经:books.studygolang.com/gopl-zh/
关于 Gopher:learnku.com/docs/go-blo…