Go常用包
Go语言中的包
包的本质:创建不同的文件夹,来存放程序文件
Go语言的源码复用建立在包(package)基础之上
main包
Go语言的入口 main()函数所在的包必须是main包
main包想要引用别的代码,则需要import导入!
包名为main的包为应用程序的入口包,其他包不能使用
package包
Src目录是以代码包的形式组织并保存Go源码文件的,每个代码包都和src目录下的文件夹一一对应,每个子目录都是一个代码包
代码包包名和文件目录名,不要求一致。比如文件目录叫hello,但是代码包包名可以声明为“main”,但是同一个目录下的源码文件第一行声明的所属包,必须一致
同一个目录下的所有go文件的第一行添加包定义,以标记该文件归属的包
package 包名
关于包的使用:
- 一个目录下的统计文件归属一个包,package的声明要一致
- package声明的包和对应的目录名可以不一致,但习惯上还是写成一致
- 同包下的函数不要导入包,可以直接使用
- main包,main()函数所在的包,其他的包不能使用
- 导入包的时候,路径要从src下书写
- 对于包外而言,在导入包的时候可以使用"包名.函数名"的方式使用包内函数
- 在包声明的上面可写关于包的注释,包注释也可以专门写在doc.go里
- 在import块里可以引用父目录,也可以引用子目录。
- 引用关系不能构成一个环。
使用包成员之前先要导入包,导入包的关键字是import
import "crypto/rand" //默认模式 rand.Function 包实现了用于加解密的更安全的随机数生成器
import R "crypto/rand" //包的别名:通过别名访问该包下的函数等
import . "crypto/rand" //简便模式:可以直接调用改包下的函数等
import _ "crypto/rand" //匿名导入:仅让该包执行init初始化函数
Go语言使用名称首字母大小写来判断一个对象(全局变量、全局常量、类型、结构字段、函数、方法)的访问权限,对于包而言同样如此。包中成员名称首字母大小写决定了该成员的访问权限。首字母大写,可被包外访问,即为public(公开的);首字母小写,则仅包内成员可以访问,即为internal(内部的)
用go mod管理工程
初始化项目:
go mod init $module_name
$module_name和目录名可以不一样。上述命令会生成go.mod文件,该文件内容形如:
module go-course
go 1.19
require (
github.com/ethereum/go-ethereum v1.10.8
)
Go依次从当前项目、GOROOT、GOPATH下寻找依赖包。
- 从当前go文件所在的目录逐级向上查找go.mod文件(假设go.mod位于目录mode_path下),里面定义了module_name,则引入包的路径为"module_name/包相对于mode_path的路径"。
- go标准库提供的包在GOROOT/src下。
- 第三方依赖包在GOPATH/pkg/mod下。
go mod tidy通过扫描当前项目中的所有代码来添加未被记录的依赖至go.mod文件或从go.mod文件中删除不再被使用的依赖。
init()函数
Go语言有一个特殊的函数init,先于main函数执行,实现包级别的初始化操作
init函数会在main函数执行之前进行执行、init用在设置包、初始化变量或者其他要在程序运行前优先完成的引导工作。
即使包被导入多次,初始化只需要一次
init函数通常被用来:
- 对变量进行初始化
- 检查/修复程序的状态
- 注册
- 运行一次计算
每个源文件中可以包含多个init函数
init不能被引用
init执行顺序
- 为了使用导入的包,首先必须将其初始化。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。这通过Golang的运行时系统控制,如下图所示:
- 初始化导入的包(递归导入)
- 对包块中声明的变量进行计算和分配初始值
- 执行包中的init函数
test文件-a.go
package test
import "fmt"
import _ "go/src/main/09_Common_package/test2"
func init() {
fmt.Println("test--init1")
}
func init() {
fmt.Println("test--init2")
}
func init() {
fmt.Println("test--init3")
}
test2文件-b.go
package test2
import "fmt"
func init() {
fmt.Println("test2-b-init-1")
}
c.go
package test2
import "fmt"
func init() {
fmt.Println("test-init-c")
}
demo.go
package main
import (
"fmt"
_ "go/src/main/09_Common_package/test"
)
func init() {
fmt.Println("main--init")
}
func main() {
fmt.Println("main")
//init函数不需要传入参数,也不会返回任何值。与main相比而言,init没有被声明,因此也不能被引用
//init()//undefined: init
}
数学计算
数学常量
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.E)//自然对数的底,2.718281828459045
fmt.Println(math.Pi)//圆周率,3.141592653589793
fmt.Println(math.Phi)//黄金分割,长/短,1.618033988749895
fmt.Println(math.MaxInt)//9223372036854775807
fmt.Println(uint64(math.MaxUint))//得先把MaxUint转成uint64才能输出,18446744073709551615
fmt.Println(math.MaxFloat64)//1.7976931348623157e+308
fmt.Println(math.SmallestNonzeroFloat64)//最小的非0且正的浮点数,5e-324
}
NaN(Not a Number)
f := math.NaN()
isNaN := math.IsNaN(f)
fmt.Println(isNaN)
常用函数
fmt.Println(math.Ceil(1.1)) //向上取整,2
fmt.Println(math.Floor(1.9)) //向下取整,1。 math.Floor(-1.9)=-2
fmt.Println(math.Trunc(1.9)) //取整数部分,1
fmt.Println(math.Modf(2.5)) //返回整数部分和小数部分,2 0.5
fmt.Println(math.Abs(-2.6)) //绝对值,2.6
fmt.Println(math.Max(4, 8)) //取二者的较大者,8
fmt.Println(math.Min(4, 8)) //取二者的较小者,4
fmt.Println(math.Mod(6.5, 3.5)) //x-Trunc(x/y)*y结果的正负号和x相同,3
fmt.Println(math.Sqrt(9)) //开平方,3
fmt.Println(math.Cbrt(9)) //开三次方,2.08008
三角函数
fmt.Println(math.Sin(1))//0.8414709848078965
fmt.Println(math.Cos(1))//0.5403023058681398
fmt.Println(math.Tan(1))//1.557407724654902
fmt.Println(math.Tanh(1))//0.7615941559557649
对数和指数
math.Log(5) //自然对数,1.60943
math.Log1p(4) //等价于Log(1+p),确保结果为正数,1.60943
math.Log10(100) //以10为底数,取对数,2
math.Log2(8) //以2为底数,取对数,3
math.Pow(3, 2) //x^y,9
math.Pow10(2) //10^x,100
math.Exp(2) //e^x,7.389
包:strings
字符串常用操作
package main
import (
"fmt"
"strings"
)
func main() {
str := "woshihuairen,yama"
//Contains 是否包含指定的内容,返回布尔值 精确查询
strbool := strings.Contains(str, "ya")
strbool2 := strings.Contains(str, "z")
fmt.Println(strbool, strbool2)
//strings.ContainsAny() 是否包含指定的任意一个内容,有一个即可,返回布尔值 模糊查询
strbool3 := strings.ContainsAny(str, "zy")
fmt.Println(strbool3)
//strings.Count() 统计指定内容 在字符串中出现的次数
strbool4 := strings.Count(str, "a")
fmt.Println(strbool4)
//strings.HasPrefix() 以XXX开头
filename := "20230213.mp4"
if strings.HasPrefix(filename, "2023") {
fmt.Println(filename)
}
//strings.HasSuffix() 以XXX结尾
if strings.HasSuffix(filename, ".mp4") {
fmt.Println("文件是mp4格式")
}
//strings.Index() 寻找指定字符串第一个出现的位置,找到返回下标,找不到返回-1
fmt.Println(strings.Index(str, "y"))
fmt.Println(strings.Index(str, "q"))
//strings.IndexAny()寻找指定字符串任意字符第一次出现的位置,找到返回下标,找不到返回-1
fmt.Println(strings.IndexAny(str, "hqw"))
fmt.Println(strings.IndexAny(str, "rq"))
//strings.LastIndex()寻找指定字符串最后一次出现的位置,找到返回下标,找不到返回-1
fmt.Println(strings.LastIndex(str, "a"))
//strings.Join()用指定符号进行字符串拼接
str2 := []string{"q", "w", "e", "r", "t", "y"}
str3 := strings.Join(str2, "-")
fmt.Println(str3)
//strings.Split()按照指定符号分割字符
str4 := strings.Split(str3, "-")
fmt.Println(str4)
//strings.Repeat()重复拼接自己
str5 := strings.Repeat("abc", 5)
fmt.Println(str5)
//strings.Replace()替换指定字符,n代表替换个数,-1替换全部
str6 := strings.Replace(str, "a", "*", -1)
fmt.Println(str6)
//strings.ToUpper()字母转大写 strings.ToLower()字母转小写
fmt.Println(strings.ToUpper(str))
fmt.Println(strings.ToLower(str))
//截取字符串 str[start:end]
str7 := str[0:5]
fmt.Println(str7)
}
包:strconv
string convert
字符串和基本类型之间的转换
package main
import (
"fmt"
"strconv"
)
func main() {
s1 := "true"
//将字符串转换成bool类型
b1, _ := strconv.ParseBool(s1)
fmt.Printf("%T\n", b1)
fmt.Println(b1)
s2 := strconv.FormatBool(b1)
fmt.Printf("%T\n", s2)
fmt.Println(s2)
s3 := "100"
i1, _ := strconv.ParseInt(s3, 10, 64)
fmt.Printf("%T\n", i1)
fmt.Println(i1)
s4 := strconv.FormatInt(100, 10)
fmt.Printf("%T\n", s4)
fmt.Println(s4)
i2, _ := strconv.Atoi("-20")
fmt.Printf("%T\n", i2)
fmt.Println(i2 + 20)
str := strconv.Itoa(30)
fmt.Printf("%T\n", str)
fmt.Println(str)
}
-
strconv.ParseBool()将字符串转成bool类型
-
strconv.FormatBool()将bool转换成字符串
-
strconv.Atoi("")将字符串快速转换成int类型
-
strconv.Itoa()将int快速转换成字符串类型
时间与时间戳
time 包
时间和日期是我们编程中经常会用到的
time包提供了时间的显示和测量用的函数
获取当前时间
package main
import (
"fmt"
"time"
)
func main() {
time1()
}
func time1() {
new := time.Now()
fmt.Println(new)
}
时间格式化
fmt.Println(new.Format("2006-01-02 15:04:05"))
fmt.Println(new.Format("2006-01-02 03:04:05 PM"))
fmt.Println(new.Format("2006-01-02 03:04"))
fmt.Println(new.Format("03:04 2006-01-02"))
fmt.Println(new.Format("2006-01-02"))
解析字符串格式的时间
new := time.Now()
//时区
loc, _ := time.LoadLocation("Asia/Shanghai")
timeObj, _ := time.ParseInLocation("2006/01/02 03:04:05", "2023/01/01 12:12:00", loc)
fmt.Println(timeObj)
时间戳
//时间戳
timestamp := time.Now().Unix()
fmt.Println(timestamp)
//时间戳转换为时间对象
time2 := time.Unix(timestamp, 0)
fmt.Println(time2)
随机数
随机数序需要调用"math/rand"包,主要注意要设置种子数,这样每次生成的结果会不断变化
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
//rand.Seed(1123123123231)
//num1 := rand.Intn(10) //Intn(10)[0,9)
//fmt.Println(num1)
//设置种子数,可以设置时间戳
rand.Seed(time.Now().Unix())
for i := 0; i < 100; i++ {
num := rand.Intn(10) + 1
fmt.Print(num, " ")
}
}
package main
import (
"fmt"
"math/rand"
)
func main() {
//创建一个Rand
source := rand.NewSource(1) //seed相同的情况下,随机数生成器产生的数列是相同的
rander := rand.New(source)
for i := 0; i < 10; i++ {
fmt.Printf("%d ", rander.Intn(100))
}
fmt.Println()
source.Seed(1) //必须重置一下Seed
rander2 := rand.New(source)
for i := 0; i < 10; i++ {
fmt.Printf("%d ", rander2.Intn(100))
}
fmt.Println()
//使用全局Rand
rand.Seed(1) //如果对两次运行没有一致性要求,可以不设seed
fmt.Println(rand.Int()) //随机生成一个整数 5577006791947779410
fmt.Println(rand.Float32()) //随机生成一个浮点数 0.9405091
fmt.Println(rand.Intn(100)) //100以内的随机整数,[0,100)47
fmt.Println(rand.Perm(100)) //把[0,100)上的整数随机打乱 [10 38 18 84 36 76 89 81 19 77 4 70 16 95 87 99 25 82 96 90 56 48 69 13 22 0 53 50 11 40 68 85 66 60 39 34 75 72 43 49 51 63 42 54 91 59 9 55 94 33 37 5 41 83 6 88 8 32 98 15 27 47 1 73 92 57 17 45 30 20 65 14 12 78 52 28 31 58 24 64 35 23 79 97 26 67 44 2 80 7 86 3 29 46 61 74 93 62 21 71]
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
rand.Shuffle(len(arr), func(i, j int) { //随机打乱一个给定的slice
arr[i], arr[j] = arr[j], arr[i]//[7 3 5 2 4 1 8 9 6]
})
fmt.Println(arr)
}
定时器与时间判断
时间间隔常量Duration
time.Durtation是time包定义的一个类型,它代表两个时间点之间经过的时间
以纳秒为单位,可表示的最长时间短大约290年
time包中定义的时间间隔类型的常量如下:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minuts = 1000 * Second
Hour = 1000 * Minuts
)
time.Duration表示1纳秒,time.Second表示1秒
定时器
package main
import (
"fmt"
"time"
)
func main() {
//ticker := time.Tick(time.Second)
//for t := range ticker {
// fmt.Println(t)
//}
for i := 0; i < 10; i++ {
fmt.Println(time.Now())
//让程序休眠一秒
time.Sleep(time.Second)
}
}
时间常用操作
Add:求一个小时之后的时间
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
later := now.Add(time.Hour)
fmt.Println(now)
fmt.Println(later)
subtime := later.Sub(now)
fmt.Println(subtime)
fmt.Println(now.Equal(later))
fmt.Println(now.After(later))
fmt.Println(now.Before(later))
}