异常处理
error
非致命错误,输出错误信息
error接口使用
import "fmt"
import "errors"
func main() {
err1 := fmt.Errorf("%s", "this is normal err1")
fmt.Println("err1 = ", err1)
err2 := errors.New("this is normal err2")
fmt.Println("err2 = ", err2)
}
error接口应用
import "fmt"
import "errors"
func MyDiv(a, b int) (result int, err error) {
err = nil
if b == 0 {
err = error.New("分母不能为0")
} else {
result = a/b
}
}
func main() {
result, err := MyDiv(10,2)
if err !=nil {
fmt.Println("err = ",err)
}else{
fmt.Println("result = ",result)
}
}
panic
致命错误,中断程序
显式调用panic
panic("this is a painc test")
数组越界导致panic
程序错误也会导致自动调用panic
recover
// 设置recover
defer func() {
// recover() // 可以打印错误信息
if err := recover() ; err != nil { // 产生了panic异常
fmt.Println(err)
}
}() // 自动调用此匿名函数
文本文件处理
字符串处理
字符串操作
- Contains:判断是否包含指定字符串;func Contains(s, substr string) bool ;判断s中是否包含substr
- Join:字符串链接;func Join(a []string, sep string) ;把slice a通过sep链接起来;
- Index:查找字符串位置;func Index(s, sep string) int ;在字符串s中查找sep所在的位置,返回位置值,找不到返回-1
- Repeat:生成重复字符串;func Repeat(s string, count int) string ;重复s字符串counter次,最后返回重复的字符串
- Replace:替换字符;func Replace(s , old, new string, n int) string ;在s字符串中,吧old字符串替换为new字符串,n表示替换次数,小于0全部替换
- Split:切割字符串;func Split(s, sep string) []string;把s字符串按照sep分割,返回slice
- Trim:首尾去除指定字符串;func Trim(s string, cutset string) string ;在s字符串的头部和尾部去除cutset指定的字符串
- Fields:去除空格符;func Fields(s string) []string ;去除s字符串的空格符,并且按照空格分隔返回slice
字符串转换
Append
Append系列函数将整数等转换为字符串后,添加到现有的字节数组中。
示例:
str := make([]byte, 0, 100)
str = strconv.AppendInt(str, 4567, 10) // 以10进制方式追加
str = strconv.AppendBool(str, false)
str = strconv.AppendQoute(str, "abcdefg")
str = strconv.AppendQouteRune(str, '单')
fmt.Println(string(str)) // 4567false"abcdefg"'单'
Format
Format系列函数把其他类型元素转化为字符串。
Parse
Parse系列函数把字符串转化为其他类型。
正则表达式
正则表达式是一种进行模式匹配和文本操作的复杂而又强大的工具。go语言中内置regexp包进行正则表达式操作。
正则表达式使用
buf := "abc azc a7c aac 888 a9c tac"
// 1.解释规则,MustCompile会解析正则表达式,如果成功返回解释器
reg1 := regexp.MustCompile(`a.c`) // 反引号
if reg1 == nil { // 解析失败,返回nil
fmt.Println("regexp error")
return
}
// 2. 根据规则提取关键信息
result1 := reg1.FindAllStringSubmatch(buf, -1) // -1:匹配所有的
fmt.Println("result1 = ", result1)
提取字符串中所有小数
buf := "3.14 567 agsdg 1.23 7. 8.99 1sdljgl 6.66 "
reg1 := regexp.MustCompile(`\d+\.\d+`) // +匹配前一个字符的1次或多次
if reg1 == nil { // 解析失败,返回nil
fmt.Println("regexp error")
return
}
result1 := reg1.FindAllString(buf, -1) // -1:匹配所有的
fmt.Println("result1 = ", result1)
匹配网页有效字段
// 反引号=原生字符串
buf := `
<html lang="zh-CN">
<head>
<title>Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国</title>
</head>
<div>哈哈<div/>
<div>嘻嘻<div/>
<div>呵呵<div/>
<div>呼呼<div/>
</html>
`
reg1 := regexp.MustCompile(`<div>(?s:(.*?))<div/>`) // (.*)只要符合条件的中间内容
if reg1 == nil { // 解析失败,返回nil
fmt.Println("regexp error")
return
}
result1 := reg1.FindAllString(buf, -1) // -1:匹配所有的
fmt.Println("result1 = ", result1)
// 过滤<></>
for _, text := range result1 {
fmt.Println("text[0] = ", text[0]) // 带<></>
fmt.Println("text[1] = ", text[1]) // 不带<></>
}
JSON处理
JSON(JavaScript Object Notation)是一种比XML更轻量级的数据交换格式。go语言内置encoding/json标准库。
通过结构体生成json
// 成员变量名 首字母必须大写
type IT struct{
Company string
Subject []string
IsOk bool
Price float64
}
func main() {
// 定义一个结构体变量,同时初始化
s := IT{"itcast", []string{"Go", "C++", "Python", "Test"}, true, 666, 666}
// 编码,根据内容生成Json文本
buf, err := json.Marshal(s) // 普通编码
buf, err := json.MarshalIndent(s, "", " ") // 格式化编码
if err != nil {
fmt.Println("err = ", err)
return
}
ftm.Println("buf = ", string(buf))
}
通过map生成json
func main() {
// 创建一个map
m := make(map[string]interface{}, 4)
m["company"] = "itcast"
m["subjects"] = []string{"Go", "C++", "Python", "Test"}
m["isok"] = true
m["price"] = 666.666
// 编码成json
result, err := json.Marshal(m) // 普通编码
if err != nil {
fmt.Println("err = ", err)
return
}
ftm.Println("result = ", string(result))
}
struct_tag使用
type IT struct{
Company string `json:"company"` // 二次编码
Subject []string `json:"-"` // 此字段不会输出到屏幕
IsOk bool `json:",string"` //转化为字符串输出
Price float64
}
解析json到结构体
需要先设定类型格式,再按格式解析取值。
type IT struct{
Company string `json:"company"` // 二次编码
}
func main() {
jsonBut := `
{
"company": "itcast"
}`
var tmp IT // 定义一个结构体变量
err := json.Unmarshal([]byte(jsonBuf), &tmp)
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Printf("tmp = %+v\n", tmp)
// 可以只取部分内容 新定义一个结构体即可
type IT2 struct {
Company string `json:"company"` // 二次编码
}
var tmp2 IT2 // 定义一个结构体变量
err2 := json.Unmarshal([]byte(jsonBuf), &tmp2)
if err2 != nil {
fmt.Println("err2 = ", err2)
return
}
fmt.Printf("tmp2 = %+v\n", tmp2)
}
解析json到map
解析操作简单,但是反推类型麻烦。
func main() {
jsonBut := `
{
"company": "itcast"
}`
// 创建一个map
m := make(map[string]interface{}, 4)
err := json.Unmarshal([]byte(jsonBuf), &m)
if err != nil {
fmt.Println("err = ", err)
return
}
fmt.Printf("m = %+v\n", m)
var str string
// 类型断言,值,是value类型
for key, value := range m {
// fmt.Printf("%v =====> %v\n", key, value)
switch data := value.(type) {
case string:
str = data // 取对的类型的值
fmt.Printf("map[%s]的值类型为 string,内容为 value = %s\n ", key, data)
case bool:
fmt.Printf("map[%s]的值类型为 bool,内容为 value = %v\n ", key, data)
case float64:
fmt.Printf("map[%s]的值类型为 float64,内容为 value = %f\n ", key, data)
case []interface{}: // 接口切片类型
fmt.Printf("map[%s]的值类型为 []interface,内容为 value = %f\n ", key, data)
}
}
}
文件操作
文件分类
- 设备文件:
屏幕(标准输出设备) fmt.Println() 往标准输出设备写内容
键盘(标准输入设备) fmt.Scan() 从标准输入设备读取内容 磁盘文件:放在存储设备上的文件
- 文本文件
- 二进制文件
为什么需要文件
内存断电后,内存中内容会清空,磁盘文件永久保存。
文件操作常用接口
- Create:根据文件名创建新文件,返回文件对象,默认权限0666;内部调用了OpenFile
- NewFile:根据文件描述符创建相应文件,返回文件对象
- Open:打开一个名称为name的文件,但是只读;内部调用了OpenFile
- OpenFile:【王者】可选择读写等
- Write:写入byte类型信息到文件
- WriteAt:在指定位置写入byte类型信息
- WriteString:写入string信息到文件
- Read:读取数据到b中
- ReadAt:从off开始读取数据到b中
- Remove:删除文件名为name的文件
标准设备文件的使用
package main
import {
"fmt"
"os"
}
func main() {
// os.Stdout.Close() // 关闭后,无法输出
fmt.Println("are u ok?") // 往标准输出设备(屏幕)写内容
// 标准设备文件(os.Stdout),默认已经打开,用户可以直接使用
os.Stdout.WriteString("are u ok?\n")
// os.Stdint.Close() // 关闭后,无法输入
var a int
fmt.Println("请输入a:")
fmt.Scan(&a) // 从标准输入设备中读取内容,放在变量a中
fmt.Println("a = ",a)
}
文件的读写
package main
import {
"fmt"
"os"
"io"
"bufio"
}
// 写文件
func WriteString (path String) {
// 新建文件
f, err := os.Create(path)
if err != nil {
fmt.Println("err = ", err)
return
}
// 使用完毕,需要关闭文件
defer f.Close()
var buf string
for i:= 0; i < 10; i++ {
// "i = 1\n",这个字符串存储在buf中
buf = fmt.Sprintf("i = %d\n", i)
f.WriteString(buf)
}
}
// 读取文件
func ReadFile(path String) {
// 打开文件
f, err := os.Open(path)
if err != nil {
fmt.Println("err = ", err)
return
}
// 关闭文件
defer f.Close()
buf := make([]byte, 1024*2) // 2k大小的切片
// n代表从文件读取内容的长度
n, err1 := f.read(buf)
if err1 != nil && err1 != io.EOF { //文件出错,同时未到结尾
fmt.Println("err1 = ", err1)
return
}
fmt.Println("buf = ", string(buf[:n]))
}
// 每次读取一行 借助bufio
func ReadFileLine(path String) {
// 打开文件
f, err := os.Open(path)
if err != nil {
fmt.Println("err = ", err)
return
}
// 关闭文件
defer f.Close()
// 新建一个缓冲区,把内容先放在缓冲区
r := bufio.NewReader(f)
for {
buf, err := r.ReadBytes('\n') // 遇到'\n'结束读取,但是\n也读取进来了
if err != nil{
if err == is.EOF{ // 文件已结束
break
}
fmt.Printf("err = ", err)
}
fmt.Printf("buf = #%s%\n", string(buf)) // buf字节切片转化为字符串
}
}
func main() {
path := "./demo.txt" // 文件路径
WriteFile(path) // 写
ReadFile(path) // 读
}
拷贝文件
实现一个拷贝文件的样例。
使用go build xxx.go 生成一个可执行文件
执行 ./copyFile x1.jpg x2.jpg 完成拷贝
package main
import (
"fmt"
"io"
"os"
)
func main() {
list := os.Args // 获取命令行参数
if len(list) != 3{ // 参数数量不足三个
fmt.Println("usage: xxx srcFile dstFile")
return
}
srcFileName := list[1]
dstFileName := list[2]
if srcFileName == dstFileName {
fmt.Println("源文件和目的文件名称不能相同")
return
}
// 只读方式打开源文件
sF,err1 := os.Open(srcFileName)
if err1 != nil {
fmt.Println("err1", err1)
return
}
// 新建目的文件
dF,err2 := os.Create(dstFileName)
if err2 != nil {
fmt.Println("err2", err2)
return
}
// 操作完毕后,关闭文件
defer sF.Close()
defer dF.Close()
// 核心数据处理,从源文件读取内容,写入到目的文件,读多少写多少
buf := make([]byte, 4*1024) //4k大小临时缓冲区
for{
n, err:= sF.Read(buf)
if err != nil{
if err == io.EOF{ // 文件读取完毕
break
}
fmt.Println("err = ", err)
}
dF.Write(buf[:n])
}
}