函数
defer
defer延迟机制,可以让资源快速释放 在函数中defer语句,将会在函数执行完后,立即执行 如果一个函数里有多个defer函数,那么defer语句会按照书写的逆序进行
// 语法
func 函数名(params paramsType) (returnVal returnType) {
defer ...
...
}
// 例子
package main
import "fmt"
func sum(n1, n2 int) int {
defer fmt.Println("这是defer")
result := n1 + n2
fmt.Println("result:", result)
}
func main() {
sum(10, 20)
}
/**
输出结果:
result:30
这是defer
*/
一般使用 defer 语句来延迟执行关闭打开的进程或文件
// 例子
package main
import (
"fmt"
"net"
"os"
)
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:3000")
if err != nil {
fmt.Println("listen err:", err)
os.Exit(1) // 结束当前进程
}
// 关闭listen
defer listen.Close()
}
注意:当 defer 和 return 遇上时,defer 会在 return 后执行
函数错误处理
判断函数是成功还是失败,可以在返回参数中加一个error参数,如果error有值则发生错误,否则函数调用成功
// 语法
func funcName(params paramsType) (returnVal returnType, err error) {
...
}
// 例子
package main
import (
"fmt"
"net"
"os"
)
// 还是这个例子 net.Listen函数 就有两个返回值
/**
net.Listen方法源代码
func Listen(network, address string) (Listener, error) {
var lc ListenConfig
return lc.Listen(context.Background(), network, address)
}
*/
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:3000")
if err != nil {
fmt.Println("listen err:", err)
os.Exit(1) // 结束当前进程
}
// 关闭listen
defer listen.Close()
}
panic 和 recover
如果函数或程序出现严重问题,不该往下执行下去,就该终止,处理这种致命的错误一般就是通过 panic 方法
// 语法
func funcName(params paramsType) (returnVals returnType) {
if (condition) {
panic("Error Info")
}
}
// 例子
package main
import "fmt"
func div(n1, n2 int) int {
if n2 == 0 {
panic("除数为 0")
}
return n1/n2
}
func main() {
result := div(2, 0)
fmt.Println("结果是:", result)
}
但是我们要想在出现 panic 后,还能继续向下执行,并将 panic 错误打印出来,这就用到我们的 recover
// 语法 recover 一般与 defer 一起使用
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
// 例子
package main
import "fmt"
func div(n1, n2 int) int {
if n2 == 0 {
panic("除数为 0")
}
return n1 / n2
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("异常报错为:", r)
}
}()
fmt.Println("开始程序")
div(2, 0)
fmt.Println("程序正常结束")
}
/**
输出结果:
开始程序
异常报错为: 除数为 0
*/
字符串(String)
注意字符串在go里只能用双引号,单引号是字符,两者不相同
String 的一些常用方法
截取字符串
// 语法
string[start : end]
| 参数 | 描述 |
|---|---|
| string | 源字符串 |
| start | 开始截取的下标,不指定默认为0 |
| end | 结束截取的下标,不指定默认为字符串长度 |
// 例子
package main
import "fmt"
func main() {
str := "Hello every body"
fmt.Println(str[1:5])
fmt.Println(str[5:])
fmt.Println(str[:10])
/**
输出结果:
ello
every body
Hello ever
*/
}
拼接字符串
- 使用 + 号
- 使用join函数拼接
- 使用buffer.WriteString函数拼接
- 使用buffer.Builder拼接
// 例子
package main
import (
"bytes"
"fmt"
"strings"
)
func main() {
str1 := "join"
str2 := " me"
// 使用 + 号
str3 := str1 + str2
// 使用 join 函数拼接 -- 类似于 JS 里的 join 函数
strSlice := []string{str1, str2}
str4 := strings.Join(strSlice, "")
// 使用buffer.WriteString函数拼接 -- 注意 Buffer 默认容量是64
var bt bytes.Buffer
bt.WriteString(str1)
bt.WriteString(str2)
str5 := bt.String()
// 使用buffer.Builder拼接
var build strings.Builder
build.WriteString(str1)
build.WriteString(str2)
str6 := build.String()
fmt.Printf("%s\n%s\n%s\n%s\n", str3, str4, str5, str6)
}
获取字符串
// 语法
len([]rune(str))
获取子串长度
// 语法
strings.Count(str, substr)
| 参数 | 描述 |
|---|---|
| str | 要获取长度的字符串 |
| substr | 子串 |
// 例子
package main
import (
"fmt"
"strings"
)
func main() {
str := "world is ours"
fmt.Println("s count is ", strings.Count(str, "s"))
fmt.Println("str len is ", len(str))
}
/**
输出结果:
s count is 2
str len is 13
*/
分割字符串
// 语法
arr := strings.Split(str,sep)
| 参数 | 描述 |
|---|---|
| str | 要分割的字符串 |
| sep | 分割符 |
// 例子
package main
import (
"fmt"
"strings"
)
func main() {
str := "we are the world"
arr := strings.Split(str, " ")
fmt.Println(arr)
/**
输出结果:
[we are the world]
*/
}
切片
因为go中的数组的长度是固定的,不可更改的,所以集合类的我们一般使用切片来代替数组的使用
创建切片
// 语法
// 这一方式创建与创建数组的区别就是没有设定元素ele的数量
varName := []type{ele1, ele2, ...}
/**
make方式
type 切片元素类型
len 切片的长度
cap 切片的容量
*/
varName := make([]type, len, [cap])
// 由数组截取创建切片的方式就不列了
1、切片容量默认是切片的长度
2、当切片的长度大于切片的容量时,切片的容量会以双倍的形式自动扩容
// 例子
package main
import "fmt"
func main() {
slice1 := []int{ 1, 2, 3, 4 }
slice2 := make([]int, 3, 4)
fmt.Printf("slice1 is %v , len is %v, cap is %v\n", slice1, len(slice1), cap(slice1))
fmt.Printf("slice2 is %v , len is %v, cap is %v\n", slice2, len(slice2), cap(slice2))
}
/**
输出结果:
slice1 is [1 2 3 4] , len is 4, cap is 4
slice2 is [0 0 0] , len is 3, cap is 4
*/
append
append为切片增加元素,返回一个新的切片
// 语法
append(slice []Type, elems ...Type) []Type
slice = append(slice, elem1, elem2)
// 也可以组合切片 注意后面要加三个点
slice = append(slice, anotherSlice...)
| 参数 | 描述 |
|---|---|
| slice | 需要添加的切片 |
| elems | 跟切片元素同类型的数据 |
// 例子
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4}
fmt.Println("slice:", slice)
// append 返回一个新的切片
slice1 := append(slice, 5, 6, 7)
fmt.Println("slice after append:", slice)
}
go 并没有提供用于删除元素的语法或接口,切片怎么删除元素呢,可以利用append可以组合slice的特性
// 例子
package main
import "fmt"
func main() {
slice := []string{"a", "b", "c", "d", "e"}
// 删除b,c
newSlice := append(slice[:1], slice[2:]...)
fmt.Println("newSlice:", newSlice)
}
/**
输出结果:
newSlice: [a d e]
*/
Map
创建map
// 语法
var mapName map[keyType]valueType
// make方法创建
var mapName = make(map[keyType]valueType, len)
// 例子
package main
import "fmt"
func main() {
// 注意最后一行也要加逗号
HotelMap := map[string]string{
"hanting": "汉庭酒店",
"juzi": "桔子酒店",
"quanji": "全季酒店",
}
fmt.Println("HotelMap:", HotelMap)
// 循环遍历
for k, v := range HotelMap {
fmt.Println("key:", k, "value:", v)
}
}
/**
输出结果:
HotelMap: map[hanting:汉庭酒店 juzi:桔子酒店 quanji:全季酒店]
key: quanji value: 全季酒店
key: hanting value: 汉庭酒店
key: juzi value: 桔子酒店
*/
判断从map是否能渠道值
// 例子
package main
import "fmt"
func main() {
// 注意最后一行也要加逗号
HotelMap := map[string]string{
"hanting": "汉庭酒店",
"juzi": "桔子酒店",
"quanji": "全季酒店",
}
fmt.Println("HotelMap:", HotelMap)
if hotel, isOk := HotelMap["juzi"]; isOk {
fmt.Println("hotel:", hotel)
}
}
删除map中的元素
// 语法
delete(mapName, KEY)
| 参数 | 描述 |
|---|---|
| mapName | 要删除的 map |
| KEY | 要删除的键 |
package main
import "fmt"
func main() {
// 注意最后一行也要加逗号
HotelMap := map[string]string{
"hanting": "汉庭酒店",
"juzi": "桔子酒店",
"quanji": "全季酒店",
}
delete(HotelMap, "quanji")
fmt.Println("HotelMap:", HotelMap)
}
/**
输出结果:
HotelMap: map[hanting:汉庭酒店 juzi:桔子酒店]
*/