Go语言24小时极速学习教程(三)常见标准库用法
常见标准库
常见标准库即Go语言自带的库,这里的所有包都可以通过import直接引入,如果你觉得实在是不好用,那么请先保证你学会了标准库的基础上,再学一下Gookit
,特别是其中的GoUtil
,千万不要轻易自己去造轮子。
1. fmt包
如果参加go语言相关算法竞赛,这个包里的以下几个函数是必学。平时工作中输出基本全用Println就足够了,主要为了打日志,平时的输入要么是接口传进来、要么是界面输入的。
- 格式化输出
fmt.Println()
:用于打印输出内容并换行,可接受多个不同类型的参数,类似于JavaScript的console.log,例如:fmt.Println("你好", 123)
。fmt.Printf()
:按照指定的格式化字符串输出内容。例如:fmt.Printf("我是 %s ,我已经 %d 岁了。\n", "萌萌", 3)
,其中%s
用于格式化字符串,%d
用于格式化整数。fmt.Errorf()
:同样也是按格式化输出,只不过是将输出内容输出到错误流上。(主流操作系统的控制台由三个流构成,即输入流、输出流、错误流)
- 格式化输入
fmt.Scan()
:从标准输入流读取用户输入,按照空格分割并将值赋给相应的变量。例如:var name string; var age int; fmt.Scan(&name, &age)
。
2. os和bufio包
- 文件操作
- 打开文件:
file, err := os.Open("test.txt")
,如果文件不存在会返回错误。 - 创建文件:
file, err := os.Create("new.txt")
。 - 读取文件内容:
- 可以使用
bufio
包结合os
包来高效读取。例如:
- 可以使用
- 打开文件:
file, err := os.Open("test.txt")
if err!= nil {
panic(err)
}
defer file.Close()
reader := bufio.NewReader(file)
line, _, err := reader.ReadLine()
if err!= nil {
panic(err)
}
fmt.Println(string(line))
写入文件内容:
file, err := os.OpenFile("test.txt", os.O_APPEND|os.O_WRONLY, 0600)
if err!= nil {
panic(err)
}
defer file.Close()
_, err = file.WriteString("这是新追加的一行\n")
if err!= nil {
panic(err)
}
- 获取操作系统相关信息
os.Getenv("PATH")
:获取环境变量PATH
的值。os.Args
:获取命令行参数,os.Args[0]
是程序名,os.Args[1:]
是传入的参数,这一点上和Java以及C#很不一样,我们往往都是通过main方法的参数来获取命令行传递的参数,而Go则是通过os包来获取命令行参数。
3. strings包
- 字符串操作
- 字符串查找:
strings.Contains("hello world", "world")
,返回true
,用于判断一个字符串是否包含另一个字符串。 - 字符串替换:
strings.Replace("hello world", "world", "golang", 1)
,将"world"
替换为"golang"
一次。 - 字符串分割:
parts := strings.Split("a,b,c", ",")
,按照逗号分割字符串,得到["a", "b", "c"]
。 - 字符串连接:
result := strings.Join([]string{"a", "b", "c"}, "-")
,将字符串切片用-
连接起来,得到"a - b - c"
。
- 字符串查找:
4. time包
- 时间获取与格式化
- 获取当前时间:
now := time.Now()
。 - 时间格式化:
fmt.Println(now.Format("2006-01-02 15:04:05"))
,一定一定要注意!Go语言中格式化时间的常量2006-01-02 15:04:05
是固定写法,不知为什么。 - 时间计算:
- 获取当前时间:
now := time.Now()
later := now.Add(time.Hour * 2)
fmt.Println(later)
5. net包
- Socket通信
TCP服务器:
ln, err := net.Listen("tcp", ":8080")
if err!= nil {
panic(err)
}
for {
conn, err := ln.Accept()
if err!= nil {
panic(err)
}
go handleConnection(conn)
}
TCP客户端:
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err!= nil {
panic(err)
}
_, err = conn.Write([]byte("你好啊,看没看到我?"))
if err!= nil {
panic(err)
}
- 访问HTTP接口
采用Get方式获取响应数据
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 发起GET请求
resp, err := http.Get("http://example.com")
if err!= nil {
fmt.Printf("请求出错: %v\n", err)
return
}
defer resp.Body.Close()
// 读取响应体内容
body, err := ioutil.ReadAll(resp.Body)
if err!= nil {
fmt.Printf("读取响应体出错: %v\n", err)
return
}
fmt.Printf("响应状态码: %d\n", resp.StatusCode)
fmt.Printf("响应内容: %s\n", string(body))
}
采用Post方式获取响应数据
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 要发送的数据
data := []byte("这是要发送的POST数据")
// 创建一个POST请求
resp, err := http.Post("http://example.com", "application/json", bytes.NewBuffer(data))
if err!= nil {
fmt.Printf("请求出错: %v\n", err)
return
}
defer resp.Body.Close()
// 读取响应体内容
body, err := ioutil.ReadAll(resp.Body)
if err!= nil {
fmt.Printf("读取响应体出错: %v\n", err)
return
}
fmt.Printf("响应状态码: %d\n", resp.StatusCode)
fmt.Printf("响应内容: %s\n", string(body))
}
6. sync包
如果你不做高并发编程,平时只是写点自动化小工具,或者只是用现成的框架搭个MVC架构写套增删改查接口,这个包基本上用不到。你如果要做消息队列、排队导出PDF、IoT项目,那一定会用到。
互斥锁(Mutex):最简单的锁,类似于Java的synchronized
var mutex sync.Mutex
var count int
func increment() {
mutex.Lock()
count++
mutex.Unlock()
}
读写锁(RWMutex):
var rwMutex sync.RWMutex
var data map[string]string
func readData() {
rwMutex.RLock()
// 读取数据操作
rwMutex.RUnlock()
}
func writeData() {
rwMutex.Lock()
// 修改数据操作
rwMutex.Unlock()
}
等待组(WaitGroup):
var wg sync.WaitGroup
func worker() {
defer wg.Done()
// 执行任务
}
wg.Add(3)
go worker()
go worker()
go worker()
wg.Wait()
7. encoding/json包
- JSON处理
结构体转JSON:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
p := Person{Name: "张三", Age: 25}
result, err := json.Marshal(p)
if err!= nil {
panic(err)
}
fmt.Println(string(result))
JSON转结构体:
jsonStr := `{"name": "李四", "age": 30}`
var p Person
err := json.Unmarshal([]byte(jsonStr), &p)
if err!= nil {
panic(err)
}
fmt.Println(p.Name, p.Age)
8.syscall包
用于调用当前操作系统内置的包或函数,比如我们在Windows下控制鼠标的移动,还需要golang.org/x/sys/windows的配合,这样就可以随时调用Win32API了。
import (
"golang.org/x/sys/windows"
"syscall"
)
func main() {
// 获取user32.dll句柄
user32, err := windows.LoadLibrary("user32.dll")
if err != nil {
panic(err)
}
defer windows.FreeLibrary(user32)
// 获取SetCursorPos函数指针
procSetCursorPos, err := windows.GetProcAddress(user32, "SetCursorPos")
if err != nil {
panic(err)
}
// 调用SetCursorPos函数设置鼠标位置
x := int32(100)
y := int32(100)
syscall.Syscall(procSetCursorPos, 2, uintptr(x), uintptr(y), 0)
}
再比如下面这个从注册表取数,获取默认打印机的例子:
import (
"fmt"
"golang.org/x/sys/windows"
"syscall"
)
func main() {
// 获取打印机信息的结构体大小
var size uint32
err := windows.GetPrinterData(windows.HKEY_CURRENT_USER,
syscall.StringToUTF16Ptr("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"),
syscall.StringToUTF16Ptr("Device"),
nil,
&size)
if err!= windows.ERROR_INSUFFICIENT_BUFFER {
fmt.Println("获取打印机信息大小失败:", err)
return
}
// 分配缓冲区
buffer := make([]uint16, size/2)
// 获取打印机信息
err = windows.GetPrinterData(windows.HKEY_CURRENT_USER,
syscall.StringToUTF16Ptr("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"),
syscall.StringToUTF16Ptr("Device"),
(*byte)(&buffer[0]),
&size)
if err!= nil {
fmt.Println("获取打印机信息失败:", err)
return
}
fmt.Printf("默认打印机名称: %s\n", windows.UTF16ToString(buffer))
}
9.其他的轮子
以下是Go语言其他次常用的内置标准库:
名称 | 作用 | 常见用法 |
---|---|---|
io | 用于处理输入输出操作,提供了对数据流的读写等功能 | io.Copy 可用于将一个io.Reader 的数据复制到一个io.Writer ,例如将一个文件的内容复制到另一个文件。buf := make([]byte, 1024) ; n, err := io.ReadFull(reader, buf) 用于从reader 读取指定长度的数据到buf 。 |
strings | 处理字符串相关操作,如查找、替换、分割等 | strings.Contains("hello world", "world") 用于判断字符串是否包含另一个字符串。strings.Replace("hello world", "world", "Go", 1) 用于替换字符串中的部分内容。parts := strings.Split("a,b,c", ",") 用于分割字符串。 |
strconv | 进行字符串和基本数据类型(如整数、浮点数等)之间的转换 | num, err := strconv.Atoi("123") 将字符串转换为整数。str := strconv.Itoa(456) 将整数转换为字符串。 |
bytes | 操作字节切片,类似于strings 库对字符串的操作,但针对字节类型 | bytes.Contains([]byte("hello"), []byte("ell")) 判断字节切片是否包含另一个字节切片。newBytes := bytes.Replace([]byte("hello"), []byte("ll"), []byte("LL"), 1) 进行字节切片的替换。 |
atomic | 提供原子操作,用于在并发环境下安全地操作变量,如原子性的增加、减少、交换等操作 | var num int32 = 5; atomic.AddInt32(&num, 1) 原子性地给num 加1。 |
math | 提供数学相关的函数,如三角函数、对数函数、幂函数等 | result := math.Sqrt(9) 计算9的平方根。sinVal := math.Sin(math.Pi / 2) 计算正弦值。 |
sort | 用于对切片进行排序操作 | 对于整数切片nums := []int{3, 1, 4, 1, 5, 9, 2, 6} ,sort.Ints(nums) 可以对其进行排序。 |