文章

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下寻找依赖包。

  1. 从当前go文件所在的目录逐级向上查找go.mod文件(假设go.mod位于目录mode_path下),里面定义了module_name,则引入包的路径为"module_name/包相对于mode_path的路径"。
  2. go标准库提供的包在GOROOT/src下。
  3. 第三方依赖包在GOPATH/pkg/mod下。

 go mod tidy通过扫描当前项目中的所有代码来添加未被记录的依赖至go.mod文件或从go.mod文件中删除不再被使用的依赖。

init()函数

Go语言有一个特殊的函数init,先于main函数执行,实现包级别的初始化操作

init函数会在main函数执行之前进行执行、init用在设置包、初始化变量或者其他要在程序运行前优先完成的引导工作。

即使包被导入多次,初始化只需要一次

init函数通常被用来:

  • 对变量进行初始化
  • 检查/修复程序的状态
  • 注册
  • 运行一次计算

每个源文件中可以包含多个init函数

init不能被引用

init执行顺序

  • 为了使用导入的包,首先必须将其初始化。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。这通过Golang的运行时系统控制,如下图所示:
  • 初始化导入的包(递归导入)
  • 对包块中声明的变量进行计算和分配初始值
  • 执行包中的init函数

image-20221225024504822

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
}

image-20221225025630748

数学计算

数学常量

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
}

image-20230314095124711

NaN(Not a Number)

	f := math.NaN()
	isNaN := math.IsNaN(f)
	fmt.Println(isNaN)

image-20230314095511986

常用函数

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)
}

image-20221225184619457

包: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)
}

image-20221225211430944

  • 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, " ")
   }
}

image-20221225221626980

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))

}

image-20221225224055032

License:  CC BY 4.0 test