5.4 常用的内置库函数
库函数(也叫标准库、系统库、内置库)是指在编程语言中内置的一些函数集合,由编程语言开发者提供并维护,可以直接在代码中使用,无需额外的下载和安装。库函数是编程语言中非常重要的组成部分,可以帮助程序员快速实现功能、提高开发效率、提高代码的可读性和可维护性,也可以提高代码的可移植性。在编程时,建议尽量使用标准库提供的函数,以提高代码质量和效率。
5.4.1 字符串操作函数
在Go语言中提供了多个内置的字符串处理函数,可以有效地帮助开发者进行字符串的处理和操作。常用的内置字符串处理函数有:
- len():返回字符串的长度。
- []byte():将字符串转换为字节切片。
- []rune():将字符串转换为Unicode字符切片。
- strconv.Itoa():将整数转换为字符串。
- strconv.Atoi():将字符串转换为整数。
- strings.Contains():判断字符串是否包含另一个字符串。
- strings.HasPrefix():判断字符串是否以另一个字符串开头。
- strings.HasSuffix():判断字符串是否以另一个字符串结尾。
- strings.Index():返回字符串中第一次出现另一个字符串的位置。
- strings.LastIndex():返回字符串中最后一次出现另一个字符串的位置。
- strings.Replace():将字符串中的指定字符替换为另一个字符。
- strings.Split():将字符串按照指定的分隔符分割成多个子串,并返回子串切片。
- strings.ToLower():将字符串转换为小写字母形式。
- strings.ToUpper():将字符串转换为大写字母形式。
- strings.TrimSpace():去掉字符串开头和结尾的空格。
- strings.Trim():去掉字符串开头和结尾指定的字符。
- strings.TrimLeft():去掉字符串开头指定的字符。
- strings.TrimRight():去掉字符串结尾指定的字符。
实例5-9:密码生成器(源码路径:Go-codes\5\pass.go)
本密码生成器可以根据用户的要求,生成一个指定长度的随机密码。实例文件pass.go的具体实现代码如下所示。
package main
import (
"fmt"
"math/rand"
"strings"
"time"
)
func generatePassword(length int, hasNum bool, hasSymbol bool) string {
rand.Seed(time.Now().UnixNano()) // 设置随机数种子
// 密码包含的字符集
var chars string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var nums string = "0123456789"
var symbols string = "~!@#$%^&*()_+{}[]\\|<>,.?/\"';:`"
if hasNum {
chars += nums
}
if hasSymbol {
chars += symbols
}
var password strings.Builder
for i := 0; i < length; i++ {
password.WriteByte(chars[rand.Intn(len(chars))])
}
return password.String()
}
func main() {
password := generatePassword(12, true, true)
fmt.Println(password)
}
在上述代码中,函数generatePassword()接受三个参数:密码长度、是否包含数字、是否包含符号。根据这些参数,函数生成一个随机密码,并返回给调用者。函数generatePassword()主要使用了以下字符串处理函数:
- rand.Seed():设置随机数种子。
- strings.Builder:使用字符串构建器来构建生成的密码。
- strings.Builder.WriteByte():将字符添加到字符串构建器中。
- strings.Builder.String():从字符串构建器中获取字符串。
- strings +=:使用“+=”运算符来将字符集添加到字符串中。
- rand.Intn():生成指定范围内的随机整数。
通过这些字符串处理函数的组合使用,我们可以实现一个简单的密码生成器,帮助用户生成高强度的随机密码。本实例的执行结果是随机的,生成随机的12位密码,例如输出:
qZnq*\I>5fGL
在这个例子中,generatePassword()函数接受三个参数:密码长度、是否包含数字、是否包含符号。根据这些参数,函数生成一个随机密码,并返回给调用者。
5.4.2 数学运算函数
在Go语言中提供了丰富的数学运算函数,包含在如下所示的包中:
- math包:该包提供了一系列的数学函数,例如Sin、Cos、Tan、Exp、Log、Sqrt等等。这些函数都是以浮点数为参数并返回浮点数结果。
- math/rand包:该包提供了随机数生成器,可以生成各种类型的随机数,例如整数、浮点数、布尔值等等。
- strconv包:该包提供了一些字符串和数字之间的转换函数,例如将一个字符串转换成一个整数、将一个整数转换成一个字符串等等。
- math/big包:该包提供了大数计算功能,可以进行高精度计算,例如大整数加减乘除、取模运算等等。
以上几个包的数学运算函数可以满足大部分数学计算的需求,同时也提供了一些高级的计算功能,例如大数计算等。需要注意的是,在使用这些函数时,需要按照具体的用法来调用相应的函数,避免出现类型不匹配、参数错误等问题。
在日常编程应用中,常用的数学函数及其功能总结如表5-1所示。
表5-1 常用的数学函数及其功能总结
函数名 | 功能 |
Abs | 求绝对值 |
Sin | 求正弦值 |
Cos | 求余弦值 |
Tan | 求正切值 |
Asin | 求反正弦值 |
Acos | 求反余弦值 |
Atan | 求反正切值 |
Atan2 | 求反正切值(带有y/x参数) |
Sqrt | 求平方根 |
Pow | 求x的y次方 |
Exp | 求e的x次方 |
Log | 求自然对数 |
Log10 | 求以10为底的对数 |
Ceil | 向上取整 |
Floor | 向下取整 |
Round | 四舍五入 |
Trunc | 取整数部分 |
Max | 取最大值 |
Min | 取最小值 |
以上是常用的数学函数,Go语言标准库中还有很多其他的数学函数,可以根据具体需求选择使用。
实例5-10:计算三角形的面积(源码路径:Go-codes\5\area.go)
实例文件area.go的具体实现代码如下所示。
package main
import (
"fmt"
"math"
)
func triangleArea(a, b, c float64) float64 {
s := (a + b + c) / 2
area := math.Sqrt(s * (s - a) * (s - b) * (s - c))
return area
}
func main() {
a, b, c := 3.0, 4.0, 5.0
area := triangleArea(a, b, c)
fmt.Printf("The area of the triangle with sides %.2f, %.2f and %.2f is %.2f\n", a, b, c, area)
}
在上述代码中,首先定义了一个函数triangleArea(),接受三个参数a、b和c表示三角形的三条边。函数首先计算半周长s,然后使用海伦公式计算三角形的面积,并将结果返回。在函数main()中,我们调用函数triangleArea(),并将三角形的三条边设为3、4和5。执行后会输出:
The area of the triangle with sides 3.00, 4.00 and 5.00 is 6.00
5.4.2 时间函数和日期函数
Go语言中的时间函数主要位于time包中,包括了多个与时间相关的函数,如下表5-2所示。
表5-2 Go语言中的时间函数
函数名 | 功能 |
time.Now() | 获取当前本地时间 |
time.Date() | 根据年月日时分秒创建时间 |
time.Parse() | 解析字符串为时间 |
time.Unix() | 根据Unix时间戳创建时间 |
time.Duration() | 将一个数值转化为Duration类型的时间 |
time.Sleep() | 使当前程序进入休眠状态 |
time.Tick() | 创建一个每隔一段时间触发的channel |
time.After() | 创建一个在一段时间后触发的channel |
time.AfterFunc() | 在一段时间后执行一个函数 |
time.Since() | 计算一个时间距离当前时间的时间差 |
time.Until() | 计算当前时间距离一个时间的时间差 |
time.Now().Format() | 时间格式化为指定字符串格式 |
time.LoadLocation() | 加载时区信息 |
time.FixedZone() | 创建固定偏移量的时区 |
time.Time.MarshalJSON() | 将时间转化为JSON格式 |
Go语言中的日期函数主要包括时间格式化、日期计算、日期比较等功能函数。下面列出了一些常用的日期函数:
(1)时间格式化函数:time.Format(format string)
该函数用于将时间类型的数据格式化为字符串类型的数据,其中format参数表示时间的格式,例如"2006-01-02 15:04:05"表示年月日时分秒的格式。
(2)时间解析函数:time.Parse(layout, value string)
该函数用于将字符串类型的日期转换为时间类型,其中layout参数表示时间的格式,value参数表示需要解析的字符串。
(3)时间加减函数:time.Add(duration Duration)
该函数用于对时间进行加减操作,其中duration参数表示时间的增加或减少量,例如time.Now().Add(24*time.Hour)表示在当前时间的基础上加上24小时。
(3)时间差函数:time.Since(t Time)
该函数用于计算当前时间与指定时间之间的时间差,返回的是Duration类型的数据,例如time.Since(startTime)表示计算从startTime到当前时间的时间差。
(4)日期比较函数:t1.Before(t2 Time)、t1.After(t2 Time)、t1.Equal(t2 Time)
这三个函数用于判断两个时间的先后关系,Before表示t1是否早于t2,After表示t1是否晚于t2,Equal表示t1和t2是否相等。
假如想要获取当前时间并格式化输出,可以使用以下代码(源码路径:Go-codes\5\time01.go)实现。
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(t.Format("2024-01-02 15:04:05"))
}
在上述代码中,函数time.Now()用于获取当前本地时间,然后使用函数t.Format()设置将时间按照指定格式进行格式化输出。
实例5-11:计算两个日期之间的天数(源码路径:Go-codes\5\time02.go)
实例文件time02.go的具体实现代码如下所示。
package main
import (
"fmt"
"math"
"time"
)
func daysBetweenDates(date1, date2 string) int {
// 将字符串格式的日期转换为 time.Time 类型
t1, _ := time.Parse("2006-01-02", date1)
t2, _ := time.Parse("2006-01-02", date2)
// 计算两个日期之间的时间差,转换为小时数
hours := t2.Sub(t1).Hours()
// 将小时数向上取整,转换为天数
days := int(math.Ceil(hours / 24))
return days
}
func main() {
date1 := "2023-01-01"
date2 := "2024-03-01"
days := daysBetweenDates(date1, date2)
fmt.Printf("在 %s 日和 %s日之间有: %d天\n", date1, date2, days)
}
在上述代码中,首先定义了函数 daysBetweenDates()来计算两个日期之间的天数。先使用函数time.Parse()将字符串格式的日期转换为 time.Time 类型。然后,我们计算两个日期之间的时间差,并将其转换为小时数。最后,我们使用函数math.Ceil()将小时数向上取整,并将其转换为天数。在主函数main()中,我们调用了函数daysBetweenDates()来计算两个日期之间的天数,并将结果输出到控制台。执行后会输出:
在 2023-01-01 日和 2024-03-01日之间有: 425天
实例5-12:密码管理器(源码路径:Go-codes\5\wan.go)
实例文件wan.go的具体实现代码如下所示。
import (
"fmt"
"time"
)
func main() {
var year, month int
fmt.Print("请输入年份:")
fmt.Scanln(&year)
fmt.Print("请输入月份:")
fmt.Scanln(&month)
// 构造时间
t := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.Local)
// 获取当月第一天是周几
weekDay := int(t.Weekday())
// 打印表头
fmt.Printf("%d年%d月\n", year, month)
fmt.Println("日\t一\t二\t三\t四\t五\t六")
// 补齐前面的空白
for i := 0; i < weekDay; i++ {
fmt.Print("\t")
}
// 循环输出日期直到下个月的第一天
for d := 1; ; d++ {
fmt.Printf("%d\t", d)
if (d + weekDay) % 7 == 0 {
fmt.Println()
}
if d >= daysInMonth(year, month) {
break
}
}
}
// 根据年份和月份返回该月的天数
func daysInMonth(year, month int) int {
switch month {
case 2:
if isLeapYear(year) {
return 29
} else {
return 28
}
case 4, 6, 9, 11:
return 30
default:
return 31
}
}
// 判断是否为闰年
func isLeapYear(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
对上述代码的具体说明如下:
- 首先从标准输入读取用户输入的年份和月份。
- 然后使用Go语言内置的 time.Date() 函数构造时间对象,并使用 time.Weekday() 方法获取当月第一天是周几。
- 在输出时,先打印表头,然后循环输出日期。在输出日期前会先补齐前面的空白,并根据每个日期所处的星期进行换行。
- 最后定义两个辅助函数 daysInMonth() 和 isLeapYear() 分别判断一个月的天数和一个年份是否为闰年。
执行后会输出:
请输入年份:2023
请输入月份:4
2023年4月
日 一 二 三 四 五 六
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
5.4.3 哈希函数
Go语言中哈希函数主要由标准库的hash包提供,其用于将任意长度的数据映射到一个固定范围的值(通常为一个整数)。哈希函数的输出值称为哈希值,也称为摘要、指纹或散列值。在Go语言中,哈希函数主要有以下几种类型:
(1)crypto.Hash:这是Go语言加密算法库中的一个类型,它提供了多个常用哈希函数的实现,如MD5、SHA1、SHA256等。这些哈希函数可用于密码学场景,以确保数据的完整性和安全性。
(2)hash.Hash:这是一个通用的哈希函数接口,它定义了基本的哈希功能。通过该接口,我们可以使用不同的哈希算法来生成哈希值。该接口包含两个核心方法,即Write()和Sum()。方法Write()用于向哈希函数输入数据,而方法Sum()则用于获取最终的哈希值。除此之外,该接口还提供了一些其他辅助方法,如Reset()、Size()、BlockSize()等。
(3)fnv.Hash:该哈希函数实现了非加密场景下的FNV-1哈希算法。它适用于字符串或字节数组等非加密数据的哈希计算。
(4)crc32.Hash:该哈希函数实现了CRC-32循环冗余校验算法。它通常用于数据传输和存储中的错误检测和纠正。
除了上述内置哈希函数,Go语言还提供了一些第三方哈希函数库,如MurmurHash、xxHash等。这些哈希函数通常比标准库中的哈希函数更快和更有效,可以根据具体场景进行选择和使用。
注意:在Go语言中使用哈希函数可以实现对数据的快速索引和查找,也可以帮助我们保障数据的完整性和安全性。
实例5-13:密码管理器(源码路径:Go-codes\5\passadmin.go)
本实例演示了如何使用哈希函数来实现一个简单的密码管理器的过程,使用Go语言的crypto/sha256哈希函数来计算用户输入的密码的哈希值,并将该哈希值存储到文件中。当用户需要验证密码时,程序会读取文件中保存的哈希值并与用户输入的密码的哈希值进行比较,以确定密码是否正确。实例文件passadmin.go的具体实现代码如下所示。
import (
"crypto/sha256"
"fmt"
"os"
)
func main() {
// 获取用户输入的密码
fmt.Print("请输入您的密码:")
var password string
fmt.Scan(&password)
// 计算密码的哈希值
hash := sha256.Sum256([]byte(password))
// 将哈希值存储到文件中
err := os.WriteFile("password.txt", hash[:], 0644)
if err != nil {
fmt.Println("无法保存密码:", err)
os.Exit(1)
}
// 验证密码
fmt.Print("请再次输入您的密码以验证:")
var verify string
fmt.Scan(&verify)
// 读取保存的哈希值
data, err := os.ReadFile("password.txt")
if err != nil {
fmt.Println("无法读取密码:", err)
os.Exit(1)
}
// 比较哈希值
if sha256.Sum256([]byte(verify)) == hash {
fmt.Println("密码正确!")
} else {
fmt.Println("密码错误!")
}
_ = data // 解决 "data declared and not used" 的问题
}
在上述代码中,首先使用fmt.Scan()函数获取用户输入的密码。然后,我们使用sha256.Sum256()函数计算密码的哈希值,并将该哈希值保存到名为“password.txt”的文件中。接下来,当用户需要验证密码时,程序会读取保存的哈希值,并使用sha256.Sum256()函数计算用户输入密码的哈希值。通过比较这两个哈希值,我们可以确定用户输入密码是否正确。执行后会输出:
请输入您的密码:666888
请再次输入您的密码以验证:666888
密码正确!
注意:本实例演示了如何使用哈希函数来保护用户的密码,并证明了哈希函数在密码学场景中的重要性和应用价值。将读取哈希值的结果存储在了名为data的变量中,并通过添加一个下划线对该变量进行了“使用”,以消除“declared and not used”的编译器警告。