【Go基础】包与工程化和常用标准库

news2024/11/15 21:40:19

文章目录

  • 一、包与工程化
    • 1. 用go mod管理工程
    • 2. 包引入规则
    • 3. init调用链
    • 4. 可见性
  • 二、常用标准库
    • 1. 数学计算
    • 2. 时间函数
    • 3. I/O操作
    • 4. 编码

一、包与工程化

1. 用go mod管理工程

初始化项目:

go mod init $module_name

$module_name和目录名可以不一样
上述命令会生成go.mod文件,该文件内容形如:

module go-course

go 1.17

require (
    github.com/ethereum/go-ethereum v1.10.8
    github.com/gin-gonic/gin v1.7.4
)

Go依次从当前项目、GOROOT、GOPATH下寻找依赖包

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

从go1.7开始,go get只负责下载第三方依赖包,并把它加到go.mod文件里,由go install负责安装二进制文件

  • go get github.com/mailru/easyjson会在GOPATH/pkg/mod目录下生成github.com/mailru/easyjson目录
  • go install github.com/mailru/easyjson/easyjson会在GOPATH/bin下生成easyjson二进制可执行文件

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

2. 包引入规则

包的声明

  • go文件的第一行声明 package xxx
  • 在包声明的上面可写关于包的注释,包注释也可以专门写在doc.go里
  • 包名跟目录名可以不同
  • 同一个目录下,所有go文件的包名必须一致

包的引用

  • 可以直接使用同目录下其他go文件里的变量、函数、结构体
  • 跨目录使用则需要变量前加入包名,并且引入包所在的目录
imoprt "go-test/package" // go-test是model名,package是目录名
mypackage.Add() // mypackage是包名,它对应的目录是package
  • 在import块里可以引用父目录,也可以引用子目录
  • 引用关系不能构成一个环
  • 在import的目录前面可以给包起一个别名
imoprt test "go-test/package"
test.Add()

3. init调用链

main函数是go程序的唯一入口,所以main函数只能存在一个,main函数必须位于main包中,在main函数执行之前会先执行init()函数,在一个目录,甚至一个go文件里,init()可以重复定义,引入其他包时,相应包里的init()函数也会在main()函数之前被调用

在这里插入图片描述

import _ "net/http/pprof"

在目录前加一个_,代码里却没有显式地使用这个包里的函数或变量,实际上是想执行这个包里的init()函数

4. 可见性

  • 以小写字母开头命名的函数、变量、结构体只能在本包内访问
  • 以大写字母开头命名的函数、变量、结构体在其他包中也可以访问
  • 如果结构体名字以大写字母开头,而其成员变量、成员方法以小写字母开头,则这样的成员只能在本包内访问

Go中命名为internal的package,可以被平级目录和上一级目录所访问,更上层的目录不能访问,如下图c目录(internal的上一级目录)及其子孙目录之间可以任意import,但a目录和b目录不能import internal及其下属的所有目录
在这里插入图片描述
在这里插入图片描述

二、常用标准库

1. 数学计算

数学常量

math.E // 自然对数的底,2.718281828459045
math.Pi	// 圆周率,3.141592653589793
math.Phi // 黄金分割,长/短,1.618033988749895
math.MaxInt	// 9223372036854775807
uint64(math.MaxUint) // 得先把MaxUint转成uint64才能输出,18446744073709551615
math.MaxFloat64	// 1.7976931348623157e+308
math.SmallestNonzeroFloat64	// 最小的非0且正的浮点数,5e-324

NaN(Not a Number)

f := math.NaN()
math.IsNaN(f)

常用函数

math.Ceil(1.1) // 向上取整,2
math.Floor(1.9)	// 向下取整,1。 math.Floor(-1.9)=-2
math.Trunc(1.9) // 取整数部分,1
math.Modf(2.5) // 返回整数部分和小数部分,2  0.5
math.Abs(-2.6) // 绝对值,2.6
math.Max(4, 8) // 取二者的较大者,8
math.Min(4, 8) // 取二者的较小者,4
math.Mod(6.5, 3.5) // x-Trunc(x/y)*y结果的正负号和x相同,3
math.Sqrt(9) // 开平方,3
math.Cbrt(9) // 开三次方,2.08008

三角函数

math.Sin(1)
math.Cos(1)
math.Tan(1)
math.Tanh(1)

对数和指数

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

随机数生成器

// 创建一个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()) // 随机生成一个整数
fmt.Println(rand.Float32()) // 随机生成一个浮点数
fmt.Println(rand.Intn(100)) // 100以内的随机整数,[0,100)
fmt.Println(rand.Perm(100)) // 把[0,100)上的整数随机打乱
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
// 随机打乱一个给定的slice
rand.Shuffle(len(arr), func(i, j int) { 
    arr[i], arr[j] = arr[j], arr[i]
})
fmt.Println(arr)

2. 时间函数

时间的解析和格式化

TIME_FMT := "2006-01-02 15:04:05"
now := time.Now()
ts := now.Format(TIME_FMT)
loc, _ = time.LoadLocation("Asia/Shanghai")
t, _ = time.ParseInLocation(TIME_FMT, ts, loc)

时间运算

diff1 := t1.Sub(t0) // 计算t1跟t0的时间差,返回类型是time.Duration
diff2 := time.Since(t0) // 计算当前时间跟t0的时间差,返回类型是time.Duration
diff3 := time.Duration(3 * time.Hour) // Duration表示两个时刻之间的距离
t4 := t0.Add(diff3) 
t4.After(t0) // true

时间的属性

t0.Unix(), t0.UnixMilli(), t0.UnixMicro(), t0.UnixNano()
t2.Year(), t2.Month(), t2.Day(), t2.YearDay()
t2.Weekday().String(), t2.Weekday()
t1.Hour(), t1.Minute(), t1.Second()

定时执行

tm := time.NewTimer(3 * time.Second)
<-tm.C // 阻塞3秒钟
// do something
tm.Stop()

// 或者用
<-time.After(3 * time.Second) // 阻塞3秒钟

周期执行

tk := time.NewTicker(1 * time.Second)
for i := 0; i < 10; i++ {
    <-tk.C // 阻塞1秒钟
    // do something
}
tk.Stop()

3. I/O操作

格式化输出

输出格式输出内容
%t单词 true 或 false
%b表示为二进制
%d表示为十进制
%e(=%.6e)有 6 位小数部分的科学计数法,如 -1234.456e+78
%f(=%.6f)有 6 位小数部分,如 123.456123
%g根据实际情况采用 %e 或 %f 格式(获得更简洁、准确的输出)
%s直接输出字符串或者字节数组
%v值的默认格式表示
%+v类似 %v,但输出结构体时会添加字段名
%#v值的 Go 语法表示
值的类型的 Go 语法表示

标准输入

fmt.Println("please input two word")
var word1 string 
var word2 string
fmt.Scan(&word1, &word2) // 读入多个单词,空格分隔。如果输入了更多单词会被缓存起来,丢给下一次scan

fmt.Println("please input an int")
var i int
fmt.Scanf("%d", &i) // 类似于Scan,转为特定格式的数据

打开文件

func os.Open(name string) (*os.File, error)
fout, err := os.OpenFile("data/verse.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)

os.O_WRONLY以只写的方式打开文件,os.O_TRUNC把文件之前的内容先清空掉,os.O_CREATE如果文件不存在则先创建,0666新建文件的权限设置

读文件

cont := make([]byte, 10)
fin.Read(cont) // 读出len(cont)个字节,返回成功读取的字节数
fin.ReadAt(cont, int64(n)) // 从指定的位置开始读len(cont)个字节
fin.Seek(int64(n), 0) // 重新定位,whence: 0从文件开头计算偏移量,1从当前位置计算偏移量,2到文件末尾的偏移量
reader := bufio.NewReader(fin) // 读文件文件建议用bufio.Reader
for { // 无限循环
    if line, err := reader.ReadString('\n'); err != nil { // 指定分隔符
        if err == io.EOF {
            if len(line) > 0 { // 如果最后一行没有换行符,则此时最后一行就存在line里
                fmt.Println(line)
            }
            break // 已读到文件末尾
        } else {
            fmt.Printf("read file failed: %v\n", err)
        }
    } else {
        line = strings.TrimRight(line, "\n") // line里面是包含换行符的,需要去掉
        fmt.Println(line)
    }
}

写文件

defer fout.Close() // 别忘了关闭文件句柄
writer := bufio.NewWriter(fout)
writer.WriteString("明月多情应笑我")
writer.WriteString("\n") // 需要手动写入换行符

创建文件/目录

os.Create(name string) // 创建文件
os.Mkdir(name string, perm fs.FileMode) // 创建目录
os.MkdirAll(path string, perm fs.FileMode) // 增强版Mkdir,沿途的目录不存在时会一并创建
os.Rename(oldpath string, newpath string) // 给文件或目录重命名,还可以实现move的功能
os.Remove(name string) // 删除文件或目录,目录不为空时才能删除成功
os.RemoveAll(path string) // 增强版Remove,所有子目录会递归删除

遍历目录

if fileInfos, err := ioutil.ReadDir(path); err != nil {
	return err
} else {
    for _, fileInfo := range fileInfos {
    fmt.Println(fileInfo.Name())
    // 如果是目录,就递归子遍历
    if fileInfo.IsDir() {
        walk(filepath.Join(path, fileInfo.Name}
    }
}

默认的log输出到控制台

log.Printf("%d+%d=%d\n", 3, 4, 3+4)
log.Println("Hello Golang")
log.Fatalln("Bye, the world") // 日志输出后会执行os.Exit(1)

指定日志输出到文件

logWriter := log.New(fout, "[BIZ_PREFIX]", log.Ldate|log.Lmicroseconds) // 通过flag参数定义日志的格式
logWriter.Println("Hello Golang")

调用系统命令

cmd_path, err := exec.LookPath("df") // 查看系统命令所在的目录,确保命令已安装
cmd := exec.Command("df", "-h") // 相当于命令df -h,注意Command的每一个参数都不能包含空格
output, err := cmd.Output() // cmd.Output()运行命令并获得其输出结果
cmd = exec.Command("rm", "./data/test.log")
cmd.Run() // 如果不需要获得命令的输出,直接调用cmd.Run()即可

4. 编码

json是go标准库里自带的序列化工具,使用了反射,效率比较低
easyjson只针对预先定义好的json结构体对输入的json字符串进行纯字符串的截取,并将对应的json字段赋值给结构体
easyjson -all xxx.go 生成go文件中定义的结构体对应的解析,xxx.go所在的package不能是main

func easyjson.Marshal(v easyjson.Marshaler) ([]byte, error)
func easyjson.Unmarshal(data []byte, v easyjson.Unmarshaler) error

sonic是字节跳动开源的json序列化工具包,号称性能强过easyjson、jsoniter,使用起来非常方便

import "github.com/bytedance/sonic"

// Marshal
output, err := sonic.Marshal(&data) 
// Unmarshal
err := sonic.Unmarshal(input, &data) 

base64经常在http环境下用来传输较长的信息,任意byte数组都可以采用base64编码转为字符串,并且可以反解回byte数组,编码和解码的方法是公开、确定的, base64不属于加密算法

func (*base64.Encoding).EncodeToString(src []byte) string
func (*base64.Encoding).DecodeString(s string) ([]byte, error)

compress包下实现了zlib、bzip、gip、lzw等压缩算法

writer := zlib.NewWriter(fout) // 压缩
writer.Write(bytes)
reader, err := zlib.NewReader(fin) // 解压
io.Copy(os.Stdout, reader) // 把reader流里的内容拷贝给标准输出流,即文件解压后的内容打印到控制台

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenMP 原子指令设计与实现

OpenMP 原子指令设计与实现 前言 在本篇文章当中主要与大家分享一下 openmp 当中的原子指令 atomic&#xff0c;分析 #pragma omp atomic 在背后究竟做了什么&#xff0c;编译器是如何处理这条指令的。 为什么需要原子指令 加入现在有两个线程分别执行在 CPU0 和 CPU1&…

LeetCode102_102. 二叉树的层序遍历

LeetCode102_102. 二叉树的层序遍历 一、描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff…

java抽象类和接口2023026

抽象类&#xff1a; 当编写一个类时&#xff0c;常常会为该类定义一些方法&#xff0c;这些方法用以描述该类的行为方式&#xff0c;那么这些方法都有具体的方法体。但在某些情况下&#xff0c;某个父类只是知道其子类应该包含怎样的方法&#xff0c;但无法准确地知道这些子类如…

使用阿里云服务器ECS 及一些问题白话阐述

阿里云服务器ECS的申请流程 首先登录阿里云官网 https://www.aliyun.com/ 查看产品文档学习观看然后看完后 大致有了了解后 我们按照我下面梳理的流程走首先购买阿里云服务器点击产品 下拉找到 云服务器ECS 然后点击进入进入到ECS的页面如果你是新人可以享受优惠购买因为还是比…

Linux常用命令——strace命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) strace 跟踪系统调用和信号 补充说明 strace命令是一个集诊断、调试、统计与一体的工具&#xff0c;我们可以使用strace对应用的系统调用和信号传递的跟踪结果来对应用进行分析&#xff0c;以达到解决问题或者…

go test的简单使用

go test go 集成了比较好用的test测试命令&#xff0c;该命令可以测试Go代码的可用性。 前奏 该文所需的项目目录结构为: example||---------function.go||---------function_test.go||---------go.modfunction.go文件是我们写用户代码的地方&#xff0c;function_test.go文…

力扣(LeetCode)388. 文件的最长绝对路径(2023.01.21)

假设有一个同时存储文件和目录的文件系统。下图展示了文件系统的一个示例&#xff1a; 这里将 dir 作为根目录中的唯一目录。dir 包含两个子目录 subdir1 和 subdir2 。subdir1 包含文件 file1.ext 和子目录 subsubdir1&#xff1b;subdir2 包含子目录 subsubdir2&#xff0c;…

架构设计中的布隆过滤器与布谷鸟过滤器

场景: 某业务后端涉及数据库&#xff0c;当请求消息查询某些信息时&#xff0c;可能先检查缓存中是否有相关信息&#xff0c;有的话返回&#xff0c;如果没有的话可能就要去数据库里面查询&#xff0c;这时候有一个问题&#xff0c;如果很多请求是在请求数据库根本不存在的数据…

活动星投票中国青年好网民网络评选微信的投票方式线上免费投票

“中国青年好网民”网络评选投票_投票微信搭建程序_微信多项免费投票_如何利用微信群投票如果通过一个小程序免费制作一个微信投票活动呢&#xff1f;文章详细讲解如何利用一款免费好用的微信小程序“活动星投票”小程序来制作投票活动&#xff0c;无需注册即可免费制作&#x…

“华为杯”研究生数学建模竞赛2005年-【华为杯】A题:高速公路行车时间估计及最优路径选择问题(附获奖论文)

赛题描述 A: Highway Traveling time Estimate and Optimal Routing Ⅰ Highway traveling time estimate is crucial to travelers. Hence, detectors are mounted on some of the US highways. For instance, detectors are mounted on every two-way six-lane highways o…

创建者模式-建造者模式

1.概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。由于实现了构建和装配的解耦…

idea启动java项目报错——error:java: 无效的源发行版: 10

问题背景 今天在新建了一个项目的后&#xff0c;项目搭建好以后&#xff0c;想要看一下是否能够正常启动。但是在启动项目的时候&#xff0c;控制台报错如下&#xff1a;error:java: 无效的源发行版: 10。脑残审核&#xff0c;你告诉我哪个是广告&#xff1f;&#xff1f;&…

Linux下进程以及相关概念理解

目录 一、进程概念 二、描述进程PCB 三、查看进程 3.1 通过系统目录查看 3.2 通过ps命令查看 四、进程状态 运行状态R 睡眠状态S 磁盘休眠状态D 暂停状态T 僵尸状态Z 死亡状态X 五、僵尸进程与孤儿进程 5.1 僵尸进程 5.1.1 僵尸进程的概念 5.1.2 僵尸进程的危害…

【C++】从0到1入门C++编程学习笔记 - 核心编程篇:类和对象(上)

文章目录一、封装1.1 封装的意义1.2 struct和class区别1.3 成员属性设置为私有二、对象的初始化和清理2.1 构造函数和析构函数2.2 构造函数的分类及调用2.3 拷贝构造函数调用时机2.4 构造函数调用规则2.5 深拷贝与浅拷贝2.6 初始化列表2.7 类对象作为类成员2.8 静态成员三、C对…

day27-单元测试/日志

1.管理系统与服务器集成 1.1准备工作【应用】 需求 对之前写过的信息管理系统进行改进,实现可以通过浏览器进行访问的功能 准备工作 将资料中的管理系统代码拷贝到当前模块下 导包的代码可能报错,因为之前的包路径可能和当前代码不一致,将导包的代码修改下 业务分析 解…

【Linux】Linux下的调试器-gdb的使用

目录1.debug和release拓展2.如何使用gdb调试3.指令集我们平常调试C/C代码大多实在Windows平台下的VS中&#xff0c;在LInux中&#xff0c;我们通常使用gdb来调试代码&#xff0c;虽然我们很少在LInux上对代码进行调试&#xff0c;gdb在实际的使用中用的较少&#xff0c;但我们必…

【C++】从0到1入门C++编程学习笔记 - 核心编程篇:类和对象(下)

文章目录五、运算符重载5.1 加号运算符重载5.2 左移运算符重载5.3 递增运算符重载5.4 赋值运算符重载5.5 关系运算符重载5.6 函数调用运算符重载六、继承6.1 继承的基本语法6.2 继承方式6.3 继承中的对象模型6.4 继承中构造和析构顺序6.5 继承同名成员处理方式6.6 继承同名静态…

Java练习:面向对象进阶(上)

Java练习&#xff1a;面向对象进阶&#xff08;上&#xff09;一、定义数组工具类a. 工具类b. 测试类c. 输出结果二、定义学生工具类a. 学生类b. 工具类c. 测试类d. 输出结果三、继承和多态综合练习a. 动物类b. 饲养员类c. 狗类d. 猫类e. 测试类f. 输出结果一、定义数组工具类 …

S60v3固件备份

清理老硬盘 该删资料了 以前的N年前备份的帖子放在CSDN备份吧 没啥用的 以后用来讲故事的 大家不要介意. RM-632102.002 E5-00极限版 RM-566031.023 6730c极限固件 RM-469091.004 E52极限固件 E5-00 一代神机 RM-632 WIFI 横屏 500MP 内存256 S60V3FP2E5的ROM估计现在太难找…

Special Weekly | 瑞兔送福,Live Long and Prosper

SOFAWish 送虎迎兔各位 SOFAStack 社区的朋友好&#xff1a;我是 SOFAStack 社区的负责人鲁直&#xff0c;度过了令人难忘的虎年&#xff0c;我们即将迈入充满希望的兔年&#xff0c;在这里给大家拜个早年&#xff0c;祝大家兔年吉祥。虎年虽然有诸多的不便与艰难&#xff0c;…