包
Go语言中包的本质:文件夹,不同的文件夹可以存放不同的功能代码。
Go语言中的源码复用就是建立在包机制上的
main包
main函数所在的包,必须是main包。代表着程序的入口;
main包引入其它包,import "fmt";
main包是程序的入口,其它包不能使用,尽量使用网址作为包名;
package 包名
src:保存项目的源码路径,所有代码都用包的形式放在src文件夹下
package 声明包在哪里,不需要和文件夹名一样,但尽量使用文件夹的名字
一个目录下的所有的go文件的package必须同名;
package可以和文件夹不同名,但不建议;
同一个包下的所有go文件的函数,都可以直接调用;
import 导入包的时候,要从src开始
package pojo
// 导入其他包,需要从goworks 下面的src 目录开始导,最标准写法
// import "xuego/lesson10/service"
// 相对路径的导包,十分不建议
// import "../service"
对于外包中的函数,需要使用包名.函数名来使用
package service
import (
"fmt"
"xuego/lesson/pojo/user"
)
func userInfo() {
user.UpdateUserInfo()
fmt.Println()
}
导包方式:
可以批量导入包
import (
// 系统
""
// 自己建的包
""
// 网上下载的包
""
)
相对路径导入包 ../上一级
import "../xxx" // 不建议这样用
如果包名冲突
import (
// R "math/rand" // 可以给包起别名
// . "math/rand" // 简便模式:可以直接调用该包下的函数,不需要通过包名
_ "math/rand" // 匿名导入,只会执行这个包下的init方法
)
init函数(重点)
必须要匿名导入,才会执行这个包下的init函数。
Go语言函数中,除了main函数入口之外,还有一个十分特别的init函数。
init:初始化,在main方法执行之前执行。
init函数可以有多个,在init函数中可以设置一些包,初始化一些全局变量,建立第三方(数据库)连接、注册、检查、修复程序状态等
init函数的执行顺序问题
package main
import (
"fmt"
// 匿名导入包,会执行包下所有go文件的init函数,单个init被多个地方导入,只会执行一次
// 1、先执行导入包的init函数,单个go文件中是顺序执行的,所有go中的init函数执行完毕后,才会到main包
// 2、如果导入了多个匿名包,按照main中导入包的顺序来执行
// 3、在同一个包下的go文件如果有多个init的情况下,按照文件排放顺序来执行对应的init函数
_ "xuego/lesson05/test" // b.go -- init()
_ "xuego/lesson05/test2" // a.go c.go -- init()
)
func init() {
fmt.Println("main--init")
}
func main() {
// init函数不需要传入参数,也没有返回值,任何地方不能调用 init()
// init()
}
strings包
strings包:字符串常用操作包。
package stringsdemo
import (
"fmt"
"strings"
)
// strings 字符串常用操作包
func Test() {
// 1、字符是不能修改的
str := "hello,world"
fmt.Println(len(str))
// strings下的常用方法
// 1、判断某个字符是否包含了指定的内容
// func Contains(s, substr string) bool
fmt.Println(strings.Contains(str, "h")) // true
// 2、判断某个字符串是否包含了多个字符串中的某一个
fmt.Println(strings.ContainsAny(str, "zd")) // true
// 3、统计这个字符在指定字符串中出现的数量
// func Count(s, substr string) int
fmt.Println(strings.Count(str, "l")) // 3
fileName := "20230223.mp4"
// 4、判断字符串以什么开头
// func HasPrefix(s, prefix string) bool
if strings.HasPrefix(fileName, "2023") {
fmt.Println("找到以2023开头的文件:", fileName)
}
// 5、判断字符串以什么结尾
// func HasSuffix(s, suffix string) bool
if strings.HasSuffix(fileName, ".mp4") {
fmt.Println("找到以mp4结尾的文件:", fileName)
}
// 6、寻找这个字符串第一次出现的位置
fmt.Println(strings.Index(str, "l")) // 2
// 7、寻找这个字符串最后一次出现的位置
fmt.Println(strings.LastIndex(str, "or")) // 7
// 8、拼接字符串,数组或切片
// Join(elems []string, sep string) string
str2 := []string{"a", "b", "c", "d", "e"}
fmt.Println(strings.Join(str2, ",")) // a,b,c,d,e
// 9、通过某个格式,拆分字符串(用的最多)
// Split(s, sep string) []string
str3 := strings.Join(str2, "-")
fmt.Println(strings.Split(str3, "-")) // [a b c d e]
// 大小写
fmt.Println(strings.ToUpper(str)) // HELLO,WORLD
fmt.Println(strings.ToLower(str)) // hello,world
// 替换,n为-1表示修改所有的,n为1表示修改一个,以此类推
fmt.Println(strings.Replace(str, "l", "的", -1)) // he的的o,wor的d
// 截取字符串
str4 := str[0:5]
fmt.Println(str4) // hello
}
package main
import "xuego/lesson05/stringsdemo"
func main() {
stringsdemo.Test()
}
strconv
顾名思义:string convert 字符串转换包
在后端接收前端请求时,需要使用字符串转换包进行字符串转换处理。
package main
import (
"fmt"
"strconv"
)
// string convert = strconv
func main() {
s1 := "true"
// 字符串转化为bool(解析:parse)
// func ParseBool(str string) (bool, error)
b1, err := strconv.ParseBool(s1)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%T, %t\n", b1, b1) // bool, true
// bool转化为字符串(格式化 format)
s2 := strconv.FormatBool(b1)
fmt.Printf("%T, %s\n", s2, s2) // string, true
// 字符串转化为整数 parse
s3 := "100"
// 字符串、进制、大小
// func ParseInt(s string, base int, bitSize int) (i int64, err error)
i, _ := strconv.ParseInt(s3, 10, 64)
fmt.Printf("%T, %d\n", i, i) // int64, 100
// 整数转化为字符串 format
s4 := strconv.FormatInt(i, 10)
fmt.Printf("%T, %s\n", s4, s4) // string, 100
// 十进制数相互转换字符串的简便方法 atoi itoa
a, _ := strconv.Atoi("10")
fmt.Printf("%T, %d\n", a, a) // int, 10
s := strconv.Itoa(20)
fmt.Printf("%T, %s\n", s, s) // string, 20
}
time
所有代码都是为了处理生活中出现的业务,其中时间的处理很重要。
获取当前时间
格式化时间
定时
package main
import (
"fmt"
"time"
)
// time
func main() {
// time1()
// time2()
// time3()
// time4()
}
// 获取当前时间 now
func time1() {
// 返回值为Time结构体
// func Now() Time
now := time.Now()
// 常量信息:年月日时分秒等
year := now.Year()
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
second := now.Second()
// 2023-06-28 23:10:52
// Printf 整数补位操作 02d 如果不足两位,左侧用0补齐
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
// 格式化时间
func time2() {
// 打印当前时间
now := time.Now()
// 2023-06-28 23:22:23.6808764 +0800 CST m=+0.023741701
fmt.Println(now)
// 格式化时间 格式化模板:yyyy-MM-dd HH:mm:ss
// Go语言诞生的时间作为格式化模板:2006年1月2号下午3点4分
// 固定的格式化时间模板:2006-01-02 15:04:05 (助记 6 12345)
// 24小时制
fmt.Println(now.Format("2006-01-02 15:04:05")) // 2023-06-28 23:22:23
// 12小时制
fmt.Println(now.Format("2006-01-02 03:04:05 PM")) // 2023-06-28 11:22:23 PM
fmt.Println(now.Format("2006/01/02 15:04")) // 2023-06-28 11:22:23 PM
fmt.Println(now.Format("15:04 2006/01/02")) // 23:22 2023/06/28
fmt.Println(now.Format("2006/01/02")) // 2023/06/28
}
// 将字符串转换为时间
func time3() {
// 获取时区,Asia/Shanghai 首字母必须大写
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Println(err)
return
}
// 将字符串解析为时间
timeStr := "2023-06-28 23:22:23"
timeObj, _ := time.ParseInLocation("2006-01-02 15:04:05", timeStr, loc)
// 2023-06-28 23:22:23 +0800 CST
fmt.Println(timeObj)
// time.Time
fmt.Printf("%T\n", timeObj)
}
// 时间戳:更多会与随机数结合
func time4() {
// 时间戳 Unix 格林威治时间自1970年1月1日(00:00:00 GMT)至当前的总秒数
// 时间戳永远不会重复的
now := time.Now()
timeStamp1 := now.Unix() // 时间戳
timeStamp2 := now.UnixNano() // 纳秒时间戳
fmt.Println(timeStamp1) // 1687967128
fmt.Println(timeStamp2) // 1687967128542682700
// 通过Unix时间戳转换为Time对象
timeObj := time.Unix(timeStamp1, 0)
year := timeObj.Year()
month := timeObj.Month()
day := timeObj.Day()
hour := timeObj.Hour()
minute := timeObj.Minute()
second := timeObj.Second()
// 2023-06-28 23:45:28
// Printf 整数补位操作 02d 如果不足两位,左侧用0补齐
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
随机数
package main
import (
"fmt"
"math/rand"
"time"
)
// random随机数 - math/rand
func main() {
// 获取一个随机数
num1 := rand.Int()
fmt.Println("num1: ", num1) // num1: 5577006791947779410
// n表示0-n的范围
num2 := rand.Intn(10)
fmt.Println("num2: ", num2) // 7
// 需要一个随时变化的量作为随机数种子 - 时间戳
// 如果随机数的种子一样,那么随机数一样
timeStamp := time.Now().Unix()
// 使用时间戳设置随机数种子
rand.Seed(timeStamp)
for i := 0; i < 5; i++ {
num := rand.Intn(10)
fmt.Println(num)
}
}
定时器
时间间隔常量 Duration
time.Duration是time包定义的一个类型,它代表两个时间点经过的时间
以纳秒为单位,可表示的最长时间段大约290年。
time包中定义的时间间隔类型的常量如下:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
定时器-本身是一个通道chan
func d1() {
// 定时器,每个1秒都会被触发执行一次
ticker := time.Tick(time.Second)
for i := range ticker {
fmt.Println(i) // 2023-02-26 14:29:40.6272883 +0800 CST m=+1.024658801
}
}
时间判断
package main
import (
"fmt"
"time"
)
func main() {
// 加 减 比较 (在...之前 在...之后)
now := time.Now()
// func (t Time) Add(d Duration) Time
later := now.Add(time.Hour)
fmt.Println(later) // 2023-02-26 15:37:03.8765174 +0800 CST m=+3600.008474201
// 两个时间的差值
// func (t Time) Sub(u Time) Duration
subTime := later.Sub(now)
fmt.Println(subTime) // 1h0m0s
// 比较时间,可以用在init()方法中用来校验当地时间和网络时间是否一致
fmt.Println(now.Equal(later)) // false
fmt.Println(now.Before(later)) // true
fmt.Println(now.After(later)) // false
}
小案例:
package main
import (
"syscall"
"time"
"unsafe"
)
func main() {
ticker := time.Tick(time.Second) // 每一秒都会触发。
for i := range ticker {
msgBox(i.Format("2006-01-02 15:04:05"))
}
}
func msgBox(timeStr string) {
user32 := syscall.NewLazyDLL("user32.dll")
messageBox := user32.NewProc("MessageBoxW")
hwnd := 0 // 0表示将弹窗放在桌面的中心位置
title := "Hello"
text := timeStr
flags := 0x00000000 | 0x00000040 // 0x00000000表示弹出消息框并且默认按钮为OK,0x00000040表示消息框的图标为信息图标
messageBox.Call(uintptr(hwnd), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))), uintptr(flags))
}