go的常用的内置函数、IO操作、小综合案例
与其说是教程,更像是总结
一起学习
1. 字符串
1.1 遍历中文字符串 []rune(str) len([]rune(str))
func main(){
s := "go语言"
fmt.Println(s)
fmt.Println(len(s))
for _, ch := range s {
fmt.Printf("%c", ch)
}
fmt.Println()
fmt.Println([]byte(s))
fmt.Println(len([]byte(s)))
for _, ch := range []byte(s) {
fmt.Printf("%c", ch)
}
fmt.Println()
fmt.Println([]rune(s))
fmt.Println(len([]rune(s)))
for _, ch := range []rune(s) {
fmt.Printf("%c", ch)
}
}
go语言
14
go语言
[230 136 145 231 136 177 103 111 232 175 173 232 168 128]
14
æç±goè¯è¨
[25105 29233 103 111 35821 35328]
6
我爱go语言
1.2 常用函数 基本都用,用到的时候再记录下来
检索字符串
分割字符串
大小写转换
修剪字符串
比较字符串
1.3 相同的两个类型之间互转
// IT类型的底层是int类型
type IT int
// a的类型为IT,底层是int
var a IT = 5
// 将a(IT)转换为int,b现在是int类型
b := int(5)
// 将b(int)转换为IT,c现在是IT类型
c := IT(b)
1.4 字符串格式处理
1.int转换为字符串:Itoa()
// Itoa(): int -> string
println("a" + strconv.Itoa(32)) // a32
2.string转换为int:Atoi()
由于string可能无法转换为int,所以这个函数有两个返回值:第一个返回值是转换成int的值,第二个返回值判断是否转换成功。
// Atoi(): string -> int
i,_ := strconv.Atoi("3")
println(3 + i) // 6
// Atoi()转换失败
i,err := strconv.Atoi("a")
if err != nil {
println("converted failed")
}
3.Parse类函数用于转换字符串为给定类型的值:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。
func ParseInt(s string, base int, bitSize int) (i int64, err error)
func ParseUint(s string, base int, bitSize int) (uint64, error)
b, err := strconv.ParseBool("true")
f, err := strconv.ParseFloat("3.1415", 64)
i, err := strconv.ParseInt("-42", 10, 64)
u, err := strconv.ParseUint("42", 10, 64)
4.将给定类型格式化为string类型:FormatBool()、FormatFloat()、FormatInt()、FormatUint()。
func FormatInt(i int64, base int) string
func FormatUint(i uint64, base int) string
s := strconv.FormatBool(true)
s := strconv.FormatFloat(3.1415, 'E', -1, 64)
s := strconv.FormatInt(-42, 16)
s := strconv.FormatUint(42, 16)
5.Append类函数
AppendTP类函数用于将TP转换成字符串后append到一个slice中:AppendBool()、AppendFloat()、AppendInt()、AppendUint()。
Append类的函数和Format类的函数工作方式类似,只不过是将转换后的结果追加到一个slice中。
package main
import (
"fmt"
"strconv"
)
func main() {
// 声明一个slice
b10 := []byte("int (base 10):")
// 将转换为10进制的string,追加到slice中
b10 = strconv.AppendInt(b10, -42, 10)
fmt.Println(string(b10))
b16 := []byte("int (base 16):")
b16 = strconv.AppendInt(b16, -42, 16)
fmt.Println(string(b16))
}
int (base 10):-42
int (base 16):-2a
2. regexp正则表达式
- regexp.Compile一般处理用户输入
- regexp.MustCompile 一般自己输入(保证正确)
const text = "My email is haorongzhu@gmail.com"
const text2 = `
My email is haorongzhu@gmail.com
email1 is bac@def.org
email2 is kkk@qq.com
emial3 is sans@kn.com.cn
`
2. 1 写死判断
re, _ := regexp.Compile("haorongzhu@gmail.com")
match := re.FindString(text)
fmt.Println(match)
2.2 使用正则表达式
- ”.” 一个字符
- ”.+” 一个或多个字符
- “*+” 零个或多个字符
re2, _ := regexp.Compile(`.+@.+\..+`) //``里不会有转义字符,直接给
match2 := re2.FindString(text)
fmt.Println(match2)
- [a-zA-Z0-9] 字母和数字
re3, _ := regexp.Compile(`[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+`)
match3 := re3.FindString(text)
fmt.Println(match3)
- [a-zA-Z0-9.] 方括号中不要加\来转义!
re4, _ := regexp.Compile(`[a-zA-Z0-9]+@[a-zA-Z0-9.]+\.[a-zA-Z0-9]+`)
match4 := re4.FindAllString(text2, -1) //-1 全部
fmt.Println(match4)
- FindAllStringSubmatch 全部匹配输出
re5, _ := regexp.Compile(`([a-zA-Z0-9]+)@([a-zA-Z0-9]+)(\.[a-zA-Z0-9.]+)`)
match5 := re5.FindAllStringSubmatch(text2, -1) //-1 全部
for _, m := range match5 {
fmt.Println(m)
}
3. 随机数
3.1 生成固定的伪随机数
package main
import (
"fmt"
"math/rand"
)
var p = fmt.Println
func main() {
p(rand.Int()) //生成一个非负的伪随机数int值
p(rand.Float64()) //生成一个非负的伪随机数float64值
p(rand.Intn(n)) //生成一个非负的伪随机数[0,n]值
}
5577006791947779410
0.9405090880450124
47
3.2 生成动态的伪随机数
func main() {
//使用种子创建伪随机资源
s1 := rand.NewSource(time.Now().UnixNano())
//利用资源生成*Rand
r1 := rand.New(s1)
//调用伪随机.Rand中需要的方法,生成
p(r1.Intn(100))
}
可以简写
rand.Seed(time.Now().UnixNano())
rand.Intn()/.Float64()/......
3.3 不重复随机数
//生成count个[start,end)结束的不重复的随机数
func generateRandomNumber(start int, end int, count int) []uint64 {
//范围检查
if end < start || (end-start) < count {
return nil
}
//存放结果的slice
nums := make([]uint64, 0)
for len(nums) < count {
//生成真随机数
num, _ := rand.Int(rand.Reader, big.NewInt(9))
a := num.Uint64()
//查重
exist := false
for _, v := range nums {
if v == a {
exist = true
break
}
}
if !exist {
nums = append(nums, a)
}
}
return nums
}
4. 键盘输入
fmt.Scanln(&userName, &password)
var p = fmt.Println
func main() {
var userName string
var password string
fmt.Scanln(&userName, &password)
p(userName, " ", password)
}
I/O操作
1. 文件信息 FileInfo fileStat
在根目录下新建abc.txt文件
type fileStat struct{
name string
size int64
mode FileMode
modTime time,time
sys syscall.Stat_t
}
func main() {
printMessage("abc.txt")
}
func printMessage(filePath string) {
fileInfo, err := os.Stat(filePath)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Printf("数据类型是 %T\n", fileInfo)
fmt.Println("文件名: ", fileInfo.Name())
fmt.Println("是否为目录: ", fileInfo.IsDir())
fmt.Println("文件权限: ", fileInfo.Mode())
fmt.Println("文件最后修改的时间: ", fileInfo.ModTime())
}
}
数据类型是 *os.fileStat
文件名: abc.txt
是否为目录: false
文件权限: -rw-rw-rw-
文件最后修改的时间: 2021-07-21 16:19:50.4050098 +0800 CST
Linux的文件权限
文件权限: -rw-rw-rw-
-=0 r=4 w=2 x=1
第一位 - -> 普通文件 d -> 目录
第2-4位 所有者权限
第5-7位 所属组权限
第8-10位 其他用户权限
2. 文件路径
- filepath.IsAbs() 判断是否是绝对路径
- filepath.Rel() 获取相对路径
- filepath.Abs() 获取绝对路径
- path.Join() 拼接字符串
3. 文件常规操作
3.1 创建目录
- os.MKdir()
- os.MKdirAll()
func main() {
fileName1 := "./test1"
//创建单级目录
err := os.Mkdir(fileName1, 0777)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Yes", fileName1)
}
//创建多级目录
fileName2 := "./test2/abc/xyz"
err = os.MkdirAll(fileName2, 0421)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("yes", fileName2)
}
fileInfo, err := os.Stat(fileName1)
fmt.Println(fileInfo.Mode())
}
mkdir ./test1: Cannot create a file when that file already exists.
yes ./test2/abc/xyz
drwxrwxrwx
3.2 创建文件 os.Create(fileName1)
func main() {
fileName1 := "./test1/abc.txt"
//创建文件
file1, err := os.Create(fileName1)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("创建成功", file1)
}
}
3.3 打开和关闭文件
- os.OpneFile(filename,mode,perm) 打开文件
-
**mode:打开方式 “ ” 分隔** - perm:权限
- file.Close() 关闭文件
3.4删除文件
- os.Remove(fileName)
- os.RemoveAll(fileName)
3.5 读取文件
func main() {
//读取文件
fileName := "./abc.txt"
file, err := os.Open(fileName)
defer file.Close()
if err != nil {
fmt.Println("打开文件错误", err)
} else {
bs := make([]byte, 1024*8, 1024*8) //length capacity
n := -1
for {
n, err = file.Read(bs)
if n == 0 || err == io.EOF {
fmt.Println("读取文件结束")
break
}
fmt.Println(string(bs[:n]))
}
}
}
3.6 写入文件
- file.Write([]byte(“asbcijs nk”))
- file.WriteString(“中国字中国字中国字中国字”)
func main() {
//写入文件
file, err := os.OpenFile("./abc.txt", os.O_APPEND, os.ModePerm)
defer file.Close()
if err != nil {
fmt.Println("打开文件异常", err.Error())
} else {
n, err := file.Write([]byte("asbcijs nk"))
if err != nil {
fmt.Println(err)
} else {
fmt.Println(n)
}
n, err = file.WriteString("中国字中国字中国字中国字")
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("写入ok: ", n)
}
}
}
3.7 复制文件
io.Copy()
func main() {
//复制文件
//源文件
srcFile := "./abc.txt"
//准备生成的文件
destFile := "./test2/abc/xyz/abc2.txt"
total, err := copyFile(srcFile, destFile)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("复制完成!", total)
}
}
func copyFile(srcFile, destFile string) (int64, error) {
file1, err := os.Open(srcFile)
if err != nil {
return 0, err
}
file3, err := os.OpenFile(destFile, os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return 0, err
}
defer file3.Close()
defer file1.Close()
return io.Copy(file3, file1)
}
综合案例
广度优先搜索算法
**配置文件 maze.in **
6 5
0 1 0 0 0
0 0 0 1 0
0 1 0 1 0
1 1 1 0 0
0 1 0 0 1
0 1 0 0 0
0 1 0 0 0
0 0 0 1 0
0 1 0 1 0
1 1 1 0 0
0 1 0 0 1
0 1 0 0 0
读取文件并测试
package main
import (
"fmt"
"os"
)
/**
读取迷宫文件
*/
func readMaze(fileName string) [][]int {
//读取文件
file, err := os.Open(fileName)
if err != nil {
panic(err)
}
//读取迷宫的大小
var row, col int
fmt.Fscanf(file, "%d %d", &row, &col)
//开辟内存
maze := make([][]int, row) //开辟一块有row个([]int)的内存
for i := range maze {
maze[i] = make([]int, col) //再开辟内部的col个int内存
//读取数据
for j := range maze[i] {
fmt.Fscan(file, &maze[i][j]) //记得取地址,不然没法修改值,输出全是0
}
}
return maze
}
func main() {
//读取文件
maze := readMaze("maze/maze.in")
for _, row := range maze {
for _, val := range row {
fmt.Printf("%d ", val)
}
fmt.Println()
}
}
实现向四周走
package main
import (
"fmt"
"os"
)
/**
读取迷宫文件
*/
func readMaze(fileName string) [][]int {
//读取文件
file, err := os.Open(fileName)
if err != nil {
panic(err)
}
//读取迷宫的大小
var row, col int
fmt.Fscanf(file, "%d %d", &row, &col)
//开辟内存
maze := make([][]int, row) //开辟一块有row个([]int)的内存
for i := range maze {
maze[i] = make([]int, col) //再开辟内部的col个int内存
//读取数据
for j := range maze[i] {
fmt.Fscan(file, &maze[i][j]) //记得取地址,不然没法修改值,输出全是0
}
}
return maze
}
/**
创建一个点
*/
type point struct {
i, j int
}
/**
定义走的四个方向
*/
var dirs = [4]point{
{-1, 0}, //往前
{0, -1}, //往左
{1, 0}, //往后
{0, -1}, //往右
}
/**
实现point结构相加(go语言没有运算符重载)
func (p *point) add(r point) 可以直接传指针,直接修改,但出错不好查找
*/
func (p point) add(r point) point { //返回值类型,不容易出错
return point{p.i + r.i, p.j + r.j}
}
/**
走迷宫
迷宫、起点、终点
*/
func walk(maze [][]int, start, end point) {
//创建记录步骤的二维数组并初始化
steps := make([][]int, len(maze))
for i := range steps {
steps[i] = make([]int, len(maze[i]))
}
//创建一个队列并初始化为起点
queue := []point{start}
//退出条件,队列中有可探索的路
for len(queue) > 0 {
cur := queue[0] //获取当前位置
queue = queue[1:] //队头出列
for _, dir := range dirs {
next := cur.add(dir) //获取到四个能走的坐标
}
}
}
func main() {
//读取文件
maze := readMaze("maze/maze.in")
//for _, row := range maze {
// for _, val := range row {
// fmt.Printf("%d ", val)
// }
// fmt.Println()
//}
//走迷宫
walk(maze, point{0, 0}, point{len(maze), len(maze[0]) - 1})
}
最终代码
package main
import (
"fmt"
"os"
)
/**
读取迷宫文件
*/
func readMaze(fileName string) [][]int {
//读取文件
file, err := os.Open(fileName)
if err != nil {
panic(err)
}
//读取迷宫的大小
var row, col int
fmt.Fscanf(file, "%d %d", &row, &col)
//开辟内存
maze := make([][]int, row) //开辟一块有row个([]int)的内存
for i := range maze {
maze[i] = make([]int, col) //再开辟内部的col个int内存
//读取数据
for j := range maze[i] {
//不指定格式就不会自动补0
//注意IDE默认的空格字符,调为Linux下的
fmt.Fscan(file, &maze[i][j]) //记得取地址,不然没法修改值,输出全是0
}
}
return maze
}
/**
创建一个点
*/
type point struct {
i, j int
}
/**
定义走的四个方向
*/
var dirs = [4]point{
{-1, 0}, //往前
{0, -1}, //往左
{1, 0}, //往后
{0, 1}, //往右
}
/**
实现point结构相加(go语言没有运算符重载)
func (p *point) add(r point) 可以直接传指针,直接修改,但出错不好查找
*/
func (p point) add(r point) point { //返回值类型,不容易出错
return point{p.i + r.i, p.j + r.j}
}
/**
打印二维数组
*/
func printArr(arr [][]int) {
for _, row := range arr {
for _, val := range row {
fmt.Printf("%3d ", val) //3位对齐
}
fmt.Println()
}
}
/**
判断位置是否越界
*/
func (p point) at(grid [][]int) (int, bool) {
//上界和右界
if p.i < 0 || p.i >= len(grid) {
return 0, false
}
//左界和下界
if p.j < 0 || p.j >= len(grid[0]) {
return 0, false
}
return grid[p.i][p.j], true
}
/**
//走迷宫
//迷宫、起点、终点
//*/
func walk(maze [][]int, start, end point) [][]int {
//创建记录步骤的二维数组并初始化
steps := make([][]int, len(maze))
for i := range steps {
steps[i] = make([]int, len(maze[i]))
}
//创建一个队列并初始化为起点
queue := []point{start}
//退出条件,队列中有可探索的路
for len(queue) > 0 {
cur := queue[0] //获取当前位置
queue = queue[1:] //队头出列
//发现终点
if cur == end {
break
}
for _, dir := range dirs {
next := cur.add(dir) //获取到四个能走的坐标
val, ok := next.at(maze)
if !ok || val == 1 { //越界或撞墙了
continue
}
val, ok = next.at(steps)
if !ok || val != 0 { //越界或走了重复的路
continue
}
if next == start { //越界或走到了起点
continue
}
/**
开始探索
*/
//填充步骤数
curStep, _ := cur.at(steps)
steps[next.i][next.j] = curStep + 1
//加入队列
queue = append(queue, next)
}
}
return steps
}
func main() {
//读取文件
maze := readMaze("maze/maze.in")
//走迷宫
steps := walk(maze, point{0, 0}, point{len(maze), len(maze[0]) - 1})
printArr(steps)
}
实现将迷宫答案追加写回文件
/**
将答案写入文件
*/
func printToFile(fileName string, arr [][]int) {
//读取文件
file, err := os.OpenFile(fileName, os.O_APPEND, 0666)
if err != nil {
panic(err)
}
var str []string
str = append(str, "\n迷宫答案\n")
for _, row := range arr {
for _, val := range row {
str = append(str, strconv.Itoa(val))
}
str = append(str, "\n")
}
var d1 = []byte(fmt.Sprintf(strings.Join(str, " ")))
n, err2 := file.Write(d1) //写入文件(字节数组)
if err2 != nil || n == 0 {
panic(err2)
}
defer file.Close()
}
查看系统信息
package main
import (
"fmt"
"runtime"
"os"
)
func main() {
//操作系统
fmt.Println("GOOS:", runtime.GOOS)
//架构
fmt.Println("GOARCH:", runtime.GOARCH)
//GOROOT
fmt.Println("GOROOT:", runtime.GOROOT())
//go版本
fmt.Println("Version:", runtime.Version())
//cpu数
fmt.Println("NumCPU:", runtime.NumCPU())
if name, err := os.Hostname();err == nil {
fmt.Println(`电脑名称:`, name)
}
}
参考资料
PREVIOUS第七节 Go错误处理与测试
NEXT第九节 Go的协程