这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天。今天主要学习了Go语言基础语法及常见类库的使用,下面是我的笔记内容。
Go基础语法学习笔记
1、Go语言特性
-
高性能、高并发
go 天生支持高并发,goroutine和 channel的使用可以很好地解决并发编程的问题。
-
语法简单、学习曲线平缓
语法类似于C语言,但获得了简化,支持面向对象编程
-
丰富的标准库
Go语言由于发展的较晚,将大部分编程业务的代码都进行了封库,简化了开发过程
-
完整的工具链
代码格式化,编译,包管理,error错误检查,单元测试一应俱全,同时作为开源项目,还在不断更新迭代。
-
静态链接
go编译结构默认静态链接,部署非常方便,这点对比于java(必须jre)就很好
-
快速编译
-
跨平台
-
垃圾回收(自动gc,简化开发)(三色标记法,标记-清除算法)
2、配置开发环境
- 下载go,配置系统环境变量
- 配置VsCode或者Goland(IDEA+go插件也可)。
- Go语言中文网(有部分中文API文档,和部分学习教程)
3、基础语法
3.1、基本代码结构
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
package 打头,默认是main main包是主入口,import("包名")负责导包。func 表示函数起头 main包中被命名为main的函数可以直接执行。fmt包中显然有一个println方法,用于输出。
3.2、常量与变量
-
Go语言常用内置变量类型
-
整数类型:(u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr(指针),byte,rune(
支持中文的字符,UTF-8)(带u的表示不带符号) -
字符(串)类型:byte,rune,string
-
浮点型:float32,float64
-
布尔型:bool
3.2.1、变量的定义方法
- 方法一、var + 变量名+类型名 ,定义完成,=后接初始化值(可以省略变量名)
var a = "initial"
var b, c int = 1, 2 (int 可省略)
var (
x int = 10
y int = 20
)
-
方法二、:= 直接写变量名就行,自动解析。
f := float32(e)
Tips:方法二只能用于函数体内,对于包变量只能用方法一,函数体内变量必须使用,否则报错,包变量未必(这也是Go语言特性,编译语法严格,未使用的变量和包不能随意出现。)
3.2.2、常量的定义
const定义即可,就是把var成const
iota表示0,第二行表示1,第三行表示2,以此类推。
const (
X = iota + 2
Y = iota * iota
)
3.3、条件语句、循环语句、分支
- if else写法类似于C语言,但是if后可以不加括号,但是执行的语句必须加大括号,且左大括号一定要在条件末尾。
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
//不允许这样写
if condition
{
}
- go只有for循环,没有while,其他与C语言一致
- 分支语句,分支语句更加灵活,可以选择 任意类型的变量,也可以在case关键字后加逻辑代码
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
}
3.4、slice and map
3.4.1、从定长数组到变长切片
-
切片即数组的引用,切片长度可以改变。
切片的声明分为以下几类
- var s1[] int
- make()创建:var s3 []int = make([]int, 0, 0),两个参数分别表示长度和容量。
- := 创建 例如:s4 := []int{} s5 := []int{1, 2, 3}
- 数组切片:arr := [5]int{1, 2, 3, 4, 5} //数组 var s6 []int //切片 s6 = arr[1:4] //表示从1截取到4,前面不写默认从0截取,后面不写 默认截取到结尾 fmt.Println(s6)
- 切片是引用类型,对切片的操作就是对底层数组的操作
3.4.2、map的使用
- 定义map集合,使用make,格式如下,可以通过make或者{}方法定义。
var map1 map[int]int
map1:=make(map[int]int)
hashTable := map[int]int{}
-
delete()函数
-
delete(map,key),删除指定key
-
map实现去重的操作
hashTable := map[int]int{}
hashTable[1] = 19
if p, ok := hashTable[1]; ok {
fmt.Println(p)
}
delete(hashTable, 1)
if p, ok := hashTable[1]; ok {
fmt.Println(p)
} else {
fmt.Println("不存在这个值")
}
- 使用range可以遍历map,name age分别对应key和value
for name, age := range ageMp {
fmt.Println(name, age)
}
3.5、func与OOP
3.5.1、func函数
简单结构,func 函数名(参数列表 注意类型后置)返回值类型{函数体}
func add(a int, b int) int {
return a + bg
}
进阶结构,func 函数名 (参数列表 )(返回值列表),同时可以对返回值命名,这样在函数体内可以直接return。
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok//v,ok都可以省略的。
}
3.5.2、结构体
定义在函数外部,结构体的属性值通过首字母大小写区分是否公开(可被外界访问,大写为公开)
type user struct {
name string
password string
}
func main(){
}
3.5.3、指针
go可以获取指针,但不能对指针进行运算操作,其余与C语言类似。
3.5.4、结构体指针与结构体函数(method)
在普通函数的函数名前加(结构体变量的参数),就形成了方法,类似于java中的非静态实例方法。绑定于结构体对象上。
在传参时使用指针,是比较可取的,可以避免大对象的复制copy。
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
3.6、error
go语言 errors包可以用于定义错误,在go语言中,常常使用多返回值函数,其中必有一个返回值err(bool)来表示函数是否执行成功,借此可以捕获错误,并通过errors包的函数导出。
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
3.7、string包
-
Go 语言中可以使用反引号或者双引号来定义字符串。反引号表示原生的字符串,即不进行转义。Go 语言的字符串不支持单引号。
-
Go 语言的字符有以下两种:
-
uint8类型,或者叫 byte 型,代表了ASCII码的一个字符。
-
rune类型,代表一个 UTF-8字符。
func Compare(a, b string) int
*Compare 函数,用于比较两个字符串的大小,如果两个字符串相等,返回为 0。*
func Contains(s, substr string) bool
*检查的字符串中是否包含有某个字串或字符的需求,比如“abcdefg”是否包含“efg”或者‘a’,strings包主要提供了Contains的方法供开发者使用,返回值是布尔值。*
func HasPrefix(a string,b string ) bool
*a是否以b为前缀。*
func HasSufffix(a string,b string ) bool
*a是否以b为后缀.*
func Split(s, sep string) []string
*将字符串切分为字符数组,sep为分割符*
例如:fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
func Join(a []string, sep string) string
*拼接字符串的函数,sep为拼接符,有点像Split的逆向操作。*
3.8、其他常用工具包
-
encoding包
encoding包中有各类转换编码的函数库,例如encoding/json ,encoding/xml等
这里学习了json包
// 使用json工具
Title string `json:"title"`
//这里的标签相当于给属性变量重命名,与前端相适应
Year int `json:"year"`
Price int `json:"price"`
Actors []string `json:"actors"`
}
func main() {
movie := Movie{"钢铁侠", 2000, 2000, []string{"小罗伯特唐尼", "带飞"}}
**jsonStr, err := json.Marshal(movie)**
if err != nil {
fmt.Println("json marshal error", err)
return
}
fmt.Printf("jsonStr=%s\n", jsonStr)
}
也可以通过json来注入结构体,当然要注意格式的正确,属性变量的对应,goland自带这个工具,可以直接cv json数据,自动生成type代码。
buf, err := json.Marshal(a)
var b userInfo
err = json.Unmarshal(buf, &b)
-
time包
有各类获取时间的函数。
now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
要注意这里Go搞特殊化,格式化日期并非是使用yyyy-mm-dd而是使用了2006-01-02 15:04:05
Go1.20版本更新了三个常量,方便我们去记忆
DateTime = "2006-01-02 15:04:05" DateOnly = "2006-01-02" TimeOnly = "15:04:05"
-
strconv包
有各类字符串转数字的函数
n, _ := strconv.ParseInt("111", 10, 64),10表示10进制,64表示64位整数。
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax