阶段1 Go语言基础Day04 包管理 常用模块 单元测试
Posted 澐湮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阶段1 Go语言基础Day04 包管理 常用模块 单元测试相关的知识,希望对你有一定的参考价值。
Day04
作业1 我有一个梦想字母统计
// 我有一个梦想 中出现次数最多的top 10 字符集出现次数
package main
import (
"fmt"
"sort"
)
func main()
article := `abcdabcdabadDDDDDDDEDDDDDDDDDDcadbcABCDEFGBCDECDEDEEefghijelmnopqrsqweasdzxcxzcdffesrvsdhhdrofmflpcodDSFOEFSIOHFISOKOJXIO`
start := map[rune]int
for _, ch := range article
if ch > \'a\' && ch < \'z\' || ch > \'A\' && ch < \'Z\'
start[ch]++
// fmt.Println(start)
startSlice := make([][]int, 0, len(start))
for ch, cnt := range start
// fmt.Printf("%c:%d\\n", ch, cnt)
startSlice = append(startSlice, []intint(ch), cnt)
// fmt.Println(startSlice)
sort.Slice(startSlice, func(i, j int) bool return startSlice[i][1] > startSlice[j][1] )
// fmt.Println(startSlice)
// fmt.Println(startSlice[:10])
for index, value := range startSlice[:10]
fmt.Printf("%d %c %d\\n", index+1, value[0], value[1])
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312>go run hw01.go
1 D 22
2 d 9
3 E 7
4 c 7
5 f 5
6 O 5
7 s 4
8 F 4
9 e 4
10 b 4
*/
作业2 统计ip 状态码 流量等
3 统计
a 每个IP出现次数
b 每个状态码出现次数
c 每个IP在每个URL上产生的流量
int[][4]string
// ip url 状态码 字节大小
"1.1.1.1","/index.html","200","1000",
"1.1.1.2","/index.html","200","10000",
"1.1.1.1","/index.html","200","10000"
key:map 必须是可以使用==进行比较的数据类型
key 数据类型,ip+url =>string key
[]stringip,url
[2]stringip,url
package main
import (
"fmt"
"strconv"
)
func main()
lines := [][4]string
"1.1.1.1", "/index.html", "200", "1000",
"1.1.1.2", "/index.html", "400", "10000",
"1.1.1.1", "/index.html", "200", "10000",
ip := map[string]int
status := map[int]int
traffic := map[[2]string]int
for _, line := range lines
ip[line[0]]++
code, _ := strconv.Atoi(line[2])
status[code]++
key := [2]stringline[0], line[1]
tr, _ := strconv.Atoi(line[3])
traffic[key] += tr
fmt.Println(ip)
fmt.Println(status)
fmt.Println(traffic)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312>go run hw02.go
map[1.1.1.1:2 1.1.1.2:1]
map[200:2 400:1]
map[[1.1.1.1 /index.html]:11000 [1.1.1.2 /index.html]:10000]
*/
作业3 todolist
4 todo管理
a 编辑
请输入编辑的ID
通过ID查找=>Task =>显示
用户确认是否进行编辑(y/yes):编辑
用户输入:任务名称,开始时间,状态
//状态如果是已完成,初始化完成时间
//time.Now().Format("2006-01-02 15:04:05")
b删除
请输入编辑的ID
通过ID查找 =>Task =>显示
用户确认是否进行删除(y/yes):删除
c数据验证(用户输入数据检查)
任务名称:不能重复(新增,编辑)
编辑:
a,任务名称不变
b. 任务名称改成其他已存在的
任务状态:
新创建,开始执行,已完成,暂停
包管理
导入本地包
package models
// 包外可见
var Name = "test"
// D:\\GoWork\\src\\go_course\\day04-20230312\\todolist\\models\\task.go
package main
import (
"fmt"
"todolist/models"
)
func main()
fmt.Println(models.Name)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\todolist>go run main.go
test
*/
重复,使用别名
同一个文件夹向下package 包名 要一致
文件1
package task
// 包外可见
var Name = "test"
// D:\\GoWork\\src\\go_course\\day04-20230312\\todolist\\models\\task\\task.go
文件2
package task
var Name = "Controller Task"
// D:\\GoWork\\src\\go_course\\day04-20230312\\todolist\\controllers\\task\\task.go
文件3
import (
"fmt"
"todolist/controllers/task"
mtask "todolist/models/task"
)
func main()
fmt.Println(mtask.Name)
fmt.Println(task.Name)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\todolist>go run main.go
test
Controller Task
*/
点导入
package main
import (
"fmt"
. "todolist/controllers/task"
mtask "todolist/models/task"
)
func main()
fmt.Println(mtask.Name)
fmt.Println(Name)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\todolist>go run main.go
test
Controller Task
*/
init初始化
文件1
package task
// 包外可见
var Name = "test"
// D:\\GoWork\\src\\go_course\\day04-20230312\\todolist\\models\\task\\task.go
文件2
package task
import "fmt"
var Name = "Controller Task"
var Version string //需要在运行启动之前进行初始化
func Call()
fmt.Println("Controller Call")
//包在使用的时候自动对数据进行初始化
func init()
Version = "Controller v1.0"
fmt.Println("Controller init")
// D:\\GoWork\\src\\go_course\\day04-20230312\\todolist\\controllers\\task\\task.go
文件3
package main
import (
"fmt"
"todolist/controllers/task"
mtask "todolist/models/task"
// 1 导入 mod init name + 目录结构
// 2 包名与所在目录名称保持一致
// 3 调用时用包名 .VAR(包名不是文件名)
)
func main()
fmt.Println(mtask.Name)
fmt.Println(task.Name)
task.Call()
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\todolist>go run main.go
Controller init
test
Controller Task
Controller Call
*/
属性
修改文件2
version包外不可见,使用GetVersion对外提供只读
package task
import "fmt"
var Name = "Controller Task"
var Version string //需要在运行启动之前进行初始化
// 属性
// 包外可见
// 包外是否可以修改 => 需要在包外不能修改值
var version string
// 提供对外修改的函数(读,不可写)
func GetVersion() string
return version
func printVersion()
fmt.Println("print version call")
func Call()
fmt.Println("Controller Call")
//包在使用的时候自动对数据进行初始化
func init()
Version = "Controller v1.0"
fmt.Println("Controller init")
自己创建一个包,供导入
package strutil
func RandString() string
return "kk"
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\strutil\\rand.go
//配置秘钥
D:\\GoWork\\src\\go_course\\day04-20230312\\strutil>go mod init github.com/xxx/strutil
eval $(ssh-agent -s)
ssh-add ~/.ssh/github
//使用git上传代码
git init
git add .
git commit -sv
git remote add origin git@github.com:xxx/strutil.git
git push origin master
//使用
import "github.com/xxx/strutil"
fmt.Println(strutil.RandString())
*/
导入外部包
package main
import (
"github.com/astaxie/beego"
)
func main()
beego.Run()
//D:\\GoWork\\src\\go_course\\day04-20230312\\web\\main.go
列出所有包
D:\\GoWork\\src\\go_course\\day04-20230312\\web>go list -m all
//指定json格式
D:\\GoWork\\src\\go_course\\day04-20230312\\web>go list -m -json all
// go mod graph 和go list -m all 类似
D:\\GoWork\\src\\go_course\\day04-20230312\\\\web>go mod graph
// 老版本替换
D:\\GoWork\\src\\go_course\\day04-20230312\\web>
go mod edit --replace=golang.org/x/crypto@v1.0.0=github.com/golang/crypto@latest
//go.mod会生成如下replace语句: 请求golang.org回去github.com中找
replace golang.org/x/crypto v1.0.0 => github.com/golang/crypto latest
标准包
go list std
D:\\GoWork\\src\\go_course\\day04-20230312\\web>go list std
查看 go doc
D:\\GoWork\\src\\go_course\\day04-20230312\\web>go doc time.Now
package time // import "time"
func Now() Time
Now returns the current local time.
os包
package main
import (
"fmt"
"os"
)
func main()
fmt.Printf("%#v\\n", os.Args)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testcmd>go mod init testcmd
go: creating new go.mod: module testcmd
go: to add module requirements and sums:
go mod tidy
D:\\GoWork\\src\\go_course\\day04-20230312\\testcmd>go mod tidy
D:\\GoWork\\src\\go_course\\day04-20230312\\testcmd>go build
D:\\GoWork\\src\\go_course\\day04-20230312\\testcmd>testcmd.exe
[]string"testcmd.exe"
D:\\GoWork\\src\\go_course\\day04-20230312\\testcmd>testcmd.exe a b c d e f
[]string"testcmd.exe", "a", "b", "c", "d", "e", "f"
*/
flag
package main
import (
"flag"
"fmt"
)
//命令行中的参数进行解析=>指定的命令参数->变量
func main()
var (
host string
port int
h bool
help bool
)
// -h host -P port
//解析变量的指针,命令行中指定的参数名,默认值,帮助
flag.StringVar(&host, "H", "127.0.0.1", "连接地址")
flag.IntVar(&port, "P", 22, "连接端口")
flag.BoolVar(&h, "h", false, "帮助")
flag.BoolVar(&help, "help", false, "帮助")
flag.Usage = func()
fmt.Println("usage:testflag [-H 127.0.0.1] [-P 22]")
flag.PrintDefaults()
flag.Parse()
fmt.Println(host, port, h, help)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>go mod init testflag
go: creating new go.mod: module testflag
go: to add module requirements and sums:
go mod tidy
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>go mod tidy
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>go build
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe
127.0.0.1 22 false false
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -h
127.0.0.1 22 true false
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe --help
127.0.0.1 22 false true
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -help
127.0.0.1 22 false true
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -help -P 33 -H 1.1.1.1
1.1.1.1 33 false true
*/
修改,调用flag.Usage()
package main
import (
"flag"
"fmt"
)
//命令行中的参数进行解析=>指定的命令参数->变量
func main()
var (
host string
port int
h bool
help bool
)
// -h host -P port
//解析变量的指针,命令行中指定的参数名,默认值,帮助
flag.StringVar(&host, "H", "127.0.0.1", "连接地址")
flag.IntVar(&port, "P", 22, "连接端口")
flag.BoolVar(&h, "h", false, "帮助")
flag.BoolVar(&help, "help", false, "帮助")
flag.Usage = func()
fmt.Println("usage:testflag [-H 127.0.0.1] [-P 22]")
flag.PrintDefaults()
flag.Parse()
fmt.Println(host, port, h, help)
if h || help
flag.Usage()
//os.Exit(0) //不要在协程使用
return
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>go build
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -P 33 -H 1.1.1.1
1.1.1.1 33 false false
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -help
127.0.0.1 22 false true
usage:testflag [-H 127.0.0.1] [-P 22]
-H string
连接地址 (default "127.0.0.1")
-P int
连接端口 (default 22)
-h 帮助
-help
帮助
*/
flag.NArg()参数个数
flag.Args()切片
package main
import (
"flag"
"fmt"
)
//命令行中的参数进行解析=>指定的命令参数->变量
func main()
var (
host string
port int
h bool
help bool
)
// -h host -P port
//解析变量的指针,命令行中指定的参数名,默认值,帮助
flag.StringVar(&host, "H", "127.0.0.1", "连接地址")
flag.IntVar(&port, "P", 22, "连接端口")
flag.BoolVar(&h, "h", false, "帮助")
flag.BoolVar(&help, "help", false, "帮助")
flag.Usage = func()
fmt.Println("usage:testflag [-H 127.0.0.1] [-P 22]")
flag.PrintDefaults()
flag.Parse()
fmt.Println(host, port, h, help)
if h || help
flag.Usage()
//os.Exit(0) //不要在协程使用
return
fmt.Println(flag.NArg())
fmt.Println(flag.Args())
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe -P 33 -H 1.1.1.1 a b c
1.1.1.1 33 false false
3
[a b c]
D:\\GoWork\\src\\go_course\\day04-20230312\\testflag>testflag.exe x a b
127.0.0.1 22 false false
3
[x a b]
*/
修改为指针
package main
import (
"flag"
"fmt"
)
// 命令行中的参数进行解析=>指定的命令参数->变量
func main()
// -h host -P port
//解析变量的指针,命令行中指定的参数名,默认值,帮助
host := flag.String("H", "127.0.0.1", "连接地址")
port := flag.Int("P", 22, "连接端口")
h := flag.Bool("h", false, "帮助")
help := flag.Bool("help", false, "帮助")
flag.Usage = func()
fmt.Println("usage:testflag [-H 127.0.0.1] [-P 22]")
flag.PrintDefaults()
flag.Parse()
fmt.Printf("%T,%T,%T,%T\\n", host, port, h, help)
if *h || *help
flag.Usage()
//os.Exit(0) //不要在协程使用
return
fmt.Println(*host, *port, *h, *help)
fmt.Println(flag.NArg())
fmt.Println(flag.Args())
/*打印结果
PS D:\\GoWork\\src\\go_course\\day04-20230312\\testflag> go build
PS D:\\GoWork\\src\\go_course\\day04-20230312\\testflag> ./testflag.exe -P 33 -H 1.1.1.1 a b c
*string,*int,*bool,*bool
1.1.1.1 33 false false
3
[a b c]
PS D:\\GoWork\\src\\go_course\\day04-20230312\\testflag> ./testflag.exe x a b
*string,*int,*bool,*bool
127.0.0.1 22 false false
3
[x a b]
*/
cobra 参考
https://blog.csdn.net/inthat/article/details/123527784
记录日志
package main
import "log"
func main()
//设置格式
// flags
// log.SetFlags(log.Flags() | log.Ldate | log.Lshortfile)
// log.SetFlags(log.Flags() | log.Lshortfile)
log.SetFlags(log.Flags())
// prefix
log.SetPrefix("main:")
log.Println("我是第一条日志")
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testlog>go run main.go
main:2023/03/15 21:55:29 main.go:14: 我是第一条日志
// 默认有log.Ldate时间,默认没有文件名
D:\\GoWork\\src\\go_course\\day04-20230312\\testlog>go run main.go
main:2023/03/15 21:57:13 我是第一条日志
*/
Fatal日志
fatal执行后,直接退出了
package main
import "log"
func main()
//设置格式
// flags
// log.SetFlags(log.Flags() | log.Ldate | log.Lshortfile)
log.SetFlags(log.Flags() | log.Lshortfile)
// prefix
log.SetPrefix("main:")
log.Println("我是第一条日志")
log.Fatal("我是一个Fatal日志")
log.Println("我是第二条Println日志")
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testlog>go run main.go
main:2023/03/15 22:42:31 main.go:13: 我是第一条日志
main:2023/03/15 22:42:31 main.go:14: 我是一个Fatal日志
exit status 1
*/
Panic日志
panic日志,抛出错误
package main
import "log"
func main()
//设置格式
// flags
// log.SetFlags(log.Flags() | log.Ldate | log.Lshortfile)
log.SetFlags(log.Flags() | log.Lshortfile)
// prefix
log.SetPrefix("main:")
log.Println("我是第一条日志")
// log.Fatal("我是一个Fatal日志")
log.Panicln("我是一条panic日志")
log.Println("我是第二条Println日志")
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testlog>go run main.go
main:2023/03/15 22:45:12 main.go:13: 我是第一条日志
main:2023/03/15 22:45:12 main.go:15: 我是一条panic日志
panic: 我是一条panic日志
goroutine 1 [running]:
log.Panicln(0xc0000cdf60, 0x85c9dd, 0x7c6e65)
C:/Program Files/Go/src/log/log.go:368 +0x65
main.main()
D:/GoWork/src/go_course/day04-20230312/testlog/main.go:15 +0xb5
exit status 2
*/
定义多个日志格式
package main
import (
"log"
"os"
)
func main()
//设置格式
// flags
// log.SetFlags(log.Flags() | log.Ldate | log.Lshortfile)
log.SetFlags(log.Flags() | log.Lshortfile)
// prefix
log.SetPrefix("main:")
log.Println("我是第一条日志")
// log.Fatal("我是一个Fatal日志")
// log.Panicln("我是一条panic日志")
log.Println("我是第二条Println日志")
//DEBUG INFO WARNING ERROR
//logrus
logger := log.New(os.Stdout, "logger:", log.Flags())
logger2 := log.New(os.Stdout, "logger2:", log.Flags())
logger.Println("我是logger日志")
logger2.Println("我是logger2日志")
//标准输入/输出 fmt.Scan fmt.Println
//os.Stdin os.Stdout os.Stderr
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testlog>go run main.go
main:2023/03/15 22:53:27 main.go:16: 我是第一条日志
main:2023/03/15 22:53:27 main.go:19: 我是第二条Println日志
logger:2023/03/15 22:53:27 main.go:25: 我是logger日志
logger2:2023/03/15 22:53:27 main.go:26: 我是logger2日志
*/
时间包
时间戳
package main
import (
"fmt"
"time"
)
func main()
//1时间
now := time.Now()
fmt.Printf("%T,%#v\\n", now, now)
fmt.Println(now.Date())
fmt.Println(now.Year())
fmt.Println(now.Month())
fmt.Println(now.Day())
fmt.Println(now.Hour())
fmt.Println(now.Minute())
fmt.Println(now.Second())
//unix时间戳
fmt.Println(now.Unix())
fmt.Println(now.UnixNano())
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testtime>go run main.go
time.Time,time.Date(2023, time.March, 15, 23, 30, 1, 366743300, time.Local)
2023 March 15
2023
March
15
23
30
1
1678894201
1678894201366743300
*/
时间字符串
package main
import (
"fmt"
"time"
)
func main()
//1时间
now := time.Now()
//=> 字符串 2023-03-15 20:00:xx?
//Printf 格式化字符串 占位符
//2006 4位数字的年
//01 2位数字的月
//02 2位数字的天
//03 12进制的小时
//15 24进制的小时
//04 2位数字的分钟
//05 2位数字的秒
fmt.Println(now.Format("2006-01-02 03:04:05"))
fmt.Println(now.Format("2006年01月02日 03:04:05"))
fmt.Println(now.Format("2006年01月02日 15:04:05"))
fmt.Println(now.Format("15:04:05 2006年01月02日"))
fmt.Println(now.Format("15:04:05 02/01/2006"))
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testtime>go run main.go
2023-03-15 11:38:08
2023年03月15日 11:38:08
2023年03月15日 23:38:08
23:38:08 2023年03月15日
23:38:08 15/03/2023
*/
生成时间
package main
import (
"fmt"
"time"
)
func main()
//生成时间
year, month, day := 1990, time.March, 1
time1990 := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
fmt.Println(time1990.Format("2006-01-02 15:04:05"))
//unixtime
startTime := time.Unix(0, 0)
fmt.Println(startTime.Format("2006-01-02 15:04:05"))
//字符串
cTime, err := time.Parse("2006-01-02", "2001-12-01")
fmt.Println(cTime.Format("2006-01-02 15:04:05"), err)
cTime, err = time.Parse("2006/01/02", "2001/12/01")
fmt.Println(cTime.Format("2006-01-02 15:04:05"), err)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testtime>go run main.go
1990-03-01 00:00:00
1970-01-01 08:00:00
2001-12-01 00:00:00 <nil>
2001-12-01 00:00:00 <nil>
*/
时间区间
package main
import (
"fmt"
"time"
)
func main()
//字符串
cTime, err := time.Parse("2006-01-02", "2001-12-01")
fmt.Println(cTime.Format("2006-01-02 15:04:05"), err)
//时间区间
//生成时间区间
// now - time
dura := time.Since(cTime)
fmt.Printf("%T,%#v\\n", dura, dura)
fmt.Println(dura)
// time - now
dura02 := time.Until(cTime)
fmt.Println(dura02)
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testtime>go run main.go
1990-03-01 00:00:00
1970-01-01 08:00:00
2001-12-01 00:00:00 <nil>
time.Duration,671731385503438700
186592h3m5.5034387s
-186592h3m5.5040161s
*/
time.ParseDuration
package main
import (
"fmt"
"time"
)
func main()
// //1时间
now := time.Now()
//字符串
cTime, err := time.Parse("2006-01-02", "2001-12-01")
fmt.Println(cTime.Format("2006-01-02 15:04:05"), err)
//时间区间
//生成时间区间
// now - time
dura := time.Since(cTime)
fmt.Printf("%T,%#v\\n", dura, dura)
fmt.Println(dura)
// time - now
dura02 := time.Until(cTime)
fmt.Println(dura02)
dura03, err := time.ParseDuration("1h1m1s")
fmt.Println(dura03, err)
fmt.Println(dura03.Hours())
fmt.Println(dura03.Minutes())
fmt.Println(dura03.Seconds())
dura03, err = time.ParseDuration("1m")
fmt.Println(dura03, err)
// dayInterval, _ := time.ParseDuration("24h")
dayInterval, _ := time.ParseDuration("-24h1m")
fmt.Println(now.Add(dayInterval))
/*打印结果
D:\\GoWork\\src\\go_course\\day04-20230312\\testtime>go run main.go
2001-12-01 00:00:00 <nil>
time.Duration,671731985238049500
186592h13m5.2380495s
-186592h13m5.2385713s
1h1m1s <nil>
1.0169444444444444
61.016666666666666
3661
1m0s <nil>
2023-03-15 00:12:05.2374956 +0800 CST m=-86459.993930399
*/
判断时间
package main
import (
"fmt"
"time"
)
func main()
// //1时间
now := time.Now()
//字符串
cTime, err := time.Parse("2006-01-02", "2001-12-01")
fmt.Println(cTime.Format("2006-01-02 15:04:05"), err)
//时间区间
//生成时间区间
// now - time
dura := time.Since(cTime)
fmt.Printf("%T,%#v\\n", dura, dura)
fmt.Println(dura)
// time - now
dura02 := time.Until(cTime)
fmt.Println(dura02)
dura03, err := time.ParseDuration("1h1m1s")
fmt.Println(dura03, err)
fmt.Println(dura03.Hours())
fmt.Println(dura03.Minutes())
fmt.Println(dura03.Seconds())
dura03, err = time.ParseDuration("1m")
fmt.Println(dura03, err)
// dayInterval, _ := time.ParseDuration("24h")
dayInterval, _ := time.ParseDuration("-24h1m")
fmt.Println(now.Add(dayInterval))
//判断时间
// a>b a<b
yesterday := now.Add(dayInterval)
fmt.Println(yesterday.After(now))
fmt.Println(yesterday.Before(now))
fmt.Println(yesterday.Sub(now))
/**打印结果
S D:\\GoWork\\src\\go_course\\day04-20230312\\testtime> go run .\\main.go
2001-12-01 00:00:00 <nil>
time.Duration,672326858988808200
186757h27m38.9888082s
-186757h27m38.9894169s
1h1m1s <nil>
1.0169444444444444
61.016666666666666
3661
1m0s <nil>
2023-03-21 21:26:38.9888082 +0800 CST m=-86459.998134499
false
true
-24h1m0s
*/
时间常量
package main
import (
"fmt"
"time"
)
func main()
time.Sleep(time.Second * 3)
fmt.Println(time.Now())
/**打印结果
PS D:\\GoWork\\src\\go_course\\day04-20230312\\testtime> go run .\\main.go
2023-03-22 21:30:36.1898018 +0800 CST m=+3.011667801
*/
编码base64
StdEncoding编码
package main
import (
"encoding/base64"
"fmt"
)
func main()
//base64
//通常说的base64 0-9a-zA-Z+/ 64
fmt.Println(base64.StdEncoding.EncodeToString([]byte("abcdef")))
fmt.Println(base64.StdEncoding.EncodeToString([]byte("abcde")))
//在URL中+/特殊字符,base64url (-_替换)
// 非对齐 3的整数倍 =补齐
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testbase64> go run .\\main.go
YWJjZGVm
YWJjZGU=
*/
StdEncoding解码
package main
import (
"encoding/base64"
"fmt"
)
func main()
fmt.Println(base64.StdEncoding.EncodeToString([]byte("我是tt")))
fmt.Println(base64.StdEncoding.DecodeString("5oiR5pivdHQ="))
txt, _ := base64.StdEncoding.DecodeString("5oiR5pivdHQ=")
fmt.Println(string(txt))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testbase64> go run .\\main.go
5oiR5pivdHQ=
[230 136 145 230 152 175 116 116] <nil>
我是tt
*/
URLEncoding编码&解码
package main
import (
"encoding/base64"
"fmt"
)
func main()
fmt.Println(base64.StdEncoding.EncodeToString([]byte("我是tt")))
fmt.Println(base64.StdEncoding.DecodeString("5oiR5pivdHQ="))
txt, _ := base64.StdEncoding.DecodeString("5oiR5pivdHQ=")
fmt.Println(string(txt))
//在URL中+/特殊字符,base64url(-_)替换
fmt.Println(base64.URLEncoding.EncodeToString([]byte("我发动机开始了解开了是tt")))
txt, _ = base64.URLEncoding.DecodeString("5oiR5Y-R5Yqo5py65byA5aeL5LqG6Kej5byA5LqG5pivdHQ=")
fmt.Println(string(txt))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testbase64> go run .\\main.go
5oiR5pivdHQ=
[230 136 145 230 152 175 116 116] <nil>
我是tt
*/
RawStdEncoding&RawURLEncoding非对齐
不使用=补全
package main
import (
"encoding/base64"
"fmt"
)
func main()
fmt.Println(base64.StdEncoding.EncodeToString([]byte("我是tt")))
fmt.Println(base64.StdEncoding.DecodeString("5oiR5pivdHQ="))
txt, _ := base64.StdEncoding.DecodeString("5oiR5pivdHQ=")
fmt.Println(string(txt))
//在URL中+/特殊字符,base64url(-_)替换
fmt.Println(base64.URLEncoding.EncodeToString([]byte("我发动机开始了解开了是tt")))
txt, _ = base64.URLEncoding.DecodeString("5oiR5Y-R5Yqo5py65byA5aeL5LqG6Kej5byA5LqG5pivdHQ=")
fmt.Println(string(txt))
//非对齐
fmt.Println(base64.RawStdEncoding.EncodeToString([]byte("我发动机开始了解开了是tt")))
fmt.Println(base64.RawURLEncoding.EncodeToString([]byte("我发动机开始了解开了是tt")))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testbase64> go run .\\main.go
5oiR5pivdHQ=
[230 136 145 230 152 175 116 116] <nil>
我是tt
5oiR5Y-R5Yqo5py65byA5aeL5LqG6Kej5byA5LqG5pivdHQ=
我发动机开始了解开了是tt
5oiR5Y+R5Yqo5py65byA5aeL5LqG6Kej5byA5LqG5pivdHQ
5oiR5Y-R5Yqo5py65byA5aeL5LqG6Kej5byA5LqG5pivdHQ
*/
hex
package main
import (
"encoding/hex"
"fmt"
)
func main()
//hex 不区分大小写 %X %x
fmt.Printf("%X\\n", []byte("啦啦啦啦啦"))
fmt.Println(hex.EncodeToString([]byte("啦啦啦啦啦")))
txt, _ := hex.DecodeString("E595A6E595A6E595A6E595A6E595A6")
fmt.Println(string(txt))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhex> go run .\\main.go
E595A6E595A6E595A6E595A6E595A6
e595a6e595a6e595a6e595a6e595a6
啦啦啦啦啦
*/
hash
md5 hash => 不可逆
string (n:1) -> md5
md5 =>string
彩虹表(暴力破解)MD5表 => string
A => md5密码iamtt =>abcdef
B => md5密码iamtt =>abcdef
某一天A被脱库了 abcdef==> iamtt
加盐
md5(imtt+随机字符)=> defg
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
)
func main()
//hash算法 => 签名 (不可逆)
// MD5 sha1 sha256 sha512
fmt.Printf("%x\\n", md5.Sum([]byte("我是tt")))
//返回字符数和错误信息
fmt.Println(fmt.Printf("%x\\n", md5.Sum([]byte("我是tt"))))
//分两次传入
hasher := md5.New()
hasher.Write([]byte("我是"))
hasher.Write([]byte("tt"))
fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhash> go run .\\main.go
ff665a79fe7bf3dfa112d4966196e99b
ff665a79fe7bf3dfa112d4966196e99b
33 <nil>
ff665a79fe7bf3dfa112d4966196e99b
*/
生成随机数(randString)
两种方式生成切片,rt1指定容量,用append添加,rt2指定长度,使用索引赋值
package main
import (
"fmt"
"math/rand"
"time"
)
func init()
rand.Seed(time.Now().Unix())
func randString(n int) (string, string)
rt1 := make([]byte, 0, n)
rt2 := make([]byte, n, n)
//定义取值范围切片
chars := []byte\'a\', \'b\', \'c\', \'d\', \'e\'
//循环n次,每次生成随机数(切片范围内),获取对应的字符
for i := 0; i < n; i++
rt1 = append(rt1, chars[rand.Intn(len(chars))])
rt2[i] = chars[rand.Intn(len(chars))]
return string(rt1), string(rt2)
func main()
salt1, salt2 := randString(6)
fmt.Println(salt1, salt2)
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhash> go run .\\main.go
adaaed ceebab
*/
md5string
package main
import (
"crypto/md5"
"fmt"
"math/rand"
"time"
)
func init()
rand.Seed(time.Now().Unix())
func randString(n int) (string, string)
rt1 := make([]byte, 0, n)
rt2 := make([]byte, n, n)
//定义取值范围切片
chars := []byte\'a\', \'b\', \'c\', \'d\', \'e\'
//循环n次,每次生成随机数(切片范围内),获取对应的字符
for i := 0; i < n; i++
rt1 = append(rt1, chars[rand.Intn(len(chars))])
rt2[i] = chars[rand.Intn(len(chars))]
return string(rt1), string(rt2)
func md5String(text string, salt string) string
//sal+":"+text
bytes := []byte(salt)
bytes = append(bytes, \':\')
bytes = append(bytes, []byte(text)...)
return fmt.Sprintf("%x\\n", md5.Sum(bytes))
func main()
// //hash算法 => 签名 (不可逆)
// // MD5 sha1 sha256 sha512
// fmt.Printf("%x\\n", md5.Sum([]byte("我是tt")))
// //返回字符数和错误信息
// fmt.Println(fmt.Printf("%x\\n", md5.Sum([]byte("我是tt"))))
// //分两次传入
// hasher := md5.New()
// hasher.Write([]byte("我是"))
// hasher.Write([]byte("tt"))
// fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
//加盐+md5
salt1, salt2 := randString(6)
fmt.Println(salt1, salt2)
fmt.Println(md5String("我是tt", salt1))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhash> go run .\\main.go
ddeade ddccac
3341accdd922d89818d0e95301bedc19
*/
sha1
package main
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"fmt"
"math/rand"
"time"
)
func init()
rand.Seed(time.Now().Unix())
func randString(n int) (string, string)
rt1 := make([]byte, 0, n)
rt2 := make([]byte, n, n)
//定义取值范围切片
chars := []byte\'a\', \'b\', \'c\', \'d\', \'e\'
//循环n次,每次生成随机数(切片范围内),获取对应的字符
for i := 0; i < n; i++
rt1 = append(rt1, chars[rand.Intn(len(chars))])
rt2[i] = chars[rand.Intn(len(chars))]
return string(rt1), string(rt2)
func md5String(text string, salt string) string
//sal+":"+text
bytes := []byte(salt)
bytes = append(bytes, \':\')
bytes = append(bytes, []byte(text)...)
return fmt.Sprintf("%x\\n", md5.Sum(bytes))
func main()
// //hash算法 => 签名 (不可逆)
// // MD5 sha1 sha256 sha512
// fmt.Printf("%x\\n", md5.Sum([]byte("我是tt")))
// //返回字符数和错误信息
// fmt.Println(fmt.Printf("%x\\n", md5.Sum([]byte("我是tt"))))
// //分两次传入
// hasher := md5.New()
// hasher.Write([]byte("我是"))
// hasher.Write([]byte("tt"))
// fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
//加盐+md5
// salt1, salt2 := randString(6)
// fmt.Println(salt1, salt2)
// fmt.Println(md5String("我是tt", salt1))
fmt.Printf("%x\\n", sha1.Sum([]byte("我是tt")))
fmt.Printf("%x\\n", sha256.Sum256([]byte("我是tt")))
fmt.Printf("%x\\n", sha512.Sum512([]byte("我是tt")))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhash> go run .\\main.go
65687e1ffecfa849822e8989ff272cd2ef39b84b
685674d1fdaae933c8f8657806fccc87b1ea51b8c3faff4f1fcc10da4a03dd85
ec8ce5c566a93ac41c2adc2eba9a1fb04bf79d1cbf15d627872d7e7da655d4176b45bef6d6bd72ac2122dbc1fc496118f15b78e395c54e88b996cb53dfff6091
*/
sha1拼接
注意区分大小写
package main
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"math/rand"
"time"
)
func init()
rand.Seed(time.Now().Unix())
func randString(n int) (string, string)
rt1 := make([]byte, 0, n)
rt2 := make([]byte, n, n)
//定义取值范围切片
chars := []byte\'a\', \'b\', \'c\', \'d\', \'e\'
//循环n次,每次生成随机数(切片范围内),获取对应的字符
for i := 0; i < n; i++
rt1 = append(rt1, chars[rand.Intn(len(chars))])
rt2[i] = chars[rand.Intn(len(chars))]
return string(rt1), string(rt2)
func md5String(text string, salt string) string
//sal+":"+text
bytes := []byte(salt)
bytes = append(bytes, \':\')
bytes = append(bytes, []byte(text)...)
return fmt.Sprintf("%x\\n", md5.Sum(bytes))
func main()
// //hash算法 => 签名 (不可逆)
// // MD5 sha1 sha256 sha512
// fmt.Printf("%x\\n", md5.Sum([]byte("我是tt")))
// //返回字符数和错误信息
// fmt.Println(fmt.Printf("%x\\n", md5.Sum([]byte("我是tt"))))
// //分两次传入
// hasher := md5.New()
// hasher.Write([]byte("我是"))
// hasher.Write([]byte("tt"))
// fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
//加盐+md5
// salt1, salt2 := randString(6)
// fmt.Println(salt1, salt2)
// fmt.Println(md5String("我是tt", salt1))
fmt.Printf("%x\\n", sha1.Sum([]byte("我是tt")))
fmt.Printf("%x\\n", sha256.Sum256([]byte("我是tt")))
fmt.Printf("%x\\n", sha512.Sum512([]byte("我是tt")))
sha256Hasher := sha256.New()
sha256Hasher.Write([]byte("我是"))
sha256Hasher.Write([]byte("tt"))
fmt.Println(hex.EncodeToString(sha256Hasher.Sum(nil)))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testhash> go run .\\main.go
65687e1ffecfa849822e8989ff272cd2ef39b84b
685674d1fdaae933c8f8657806fccc87b1ea51b8c3faff4f1fcc10da4a03dd85
ec8ce5c566a93ac41c2adc2eba9a1fb04bf79d1cbf15d627872d7e7da655d4176b45bef6d6bd72ac2122dbc1fc496118f15b78e395c54e88b996cb53dfff6091
685674d1fdaae933c8f8657806fccc87b1ea51b8c3faff4f1fcc10da4a03dd85
*/
os/exec
cmd.Output()
直接用output 一般一次输出完
package main
import (
"fmt"
"os/exec"
)
func main()
cmd := exec.Command("ping", "-n", "2", "www.baidu.com")
bytes, err := cmd.Output()
fmt.Println(string(bytes), err)
/*打印结果
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testcmd> go run .\\main.go
���� Ping www.a.shifen.com [110.242.68.3] ���� 32 �ֽڵ�����:
���� 110.242.68.3 �Ļظ�: �ֽ�=32 ʱ��=13ms TTL=53
���� 110.242.68.3 �Ļظ�: �ֽ�=32 ʱ��=15ms TTL=53
110.242.68.3 �� Ping ͳ����Ϣ:
���ݰ�: �ѷ��� = 2���ѽ��� = 2����ʧ = 0 (0% ��ʧ)��
�����г̵Ĺ���ʱ��(�Ժ���Ϊ��λ):
���� = 13ms��� = 15ms��ƽ�� = 14ms
<nil>
*/
cmd.StdoutPipe() 管道
使用cmd.StdoutPipe() 到管道,一般隔一段时间输出的使用这种方式
package main
import (
"fmt"
"io"
"os"
"os/exec"
)
func main()
cmd := exec.Command("ping", "-n", "2", "www.baidu.com")
// bytes, err := cmd.Output()
// fmt.Println(string(bytes), err)
output, err := cmd.StdoutPipe()
cmd.Start()
fmt.Println(err)
//从管道拿取数据到输出,一般定时
io.Copy(os.Stdout, output)
cmd.Wait()
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testcmd> go run .\\main.go
<nil>
���� Ping www.baidu.com [110.242.68.3] ���� 32 �ֽڵ�����:
���� 110.242.68.3 �Ļظ�: �ֽ�=32 ʱ��=71ms TTL=53
���� 110.242.68.3 �Ļظ�: �ֽ�=32 ʱ��=16ms TTL=53
110.242.68.3 �� Ping ͳ����Ϣ:
���ݰ�: �ѷ��� = 2���ѽ��� = 2����ʧ = 0 (0% ��ʧ)��
�����г̵Ĺ���ʱ��(�Ժ���Ϊ��λ):
���� = 16ms��� = 71ms��ƽ�� = 43ms
*/
解决乱码问题
package main
import (
"bufio"
"fmt"
"os/exec"
"golang.org/x/text/encoding/simplifiedchinese"
)
type Charset string
const (
UTF8 = Charset("UTF-8")
GB18030 = Charset("GB18030")
)
func main()
cmd := exec.Command("ping", "-n", "2", "www.baidu.com")
// bytes, err := cmd.Output()
// fmt.Println(string(bytes), err)
output, err := cmd.StdoutPipe()
cmd.Start()
fmt.Println(err)
in := bufio.NewScanner(output)
for in.Scan()
cmdRe := ConvertByte2String(in.Bytes(), "GB18030")
fmt.Println(cmdRe)
//从管道拿取数据到输出,一般定时
// io.Copy(os.Stdout, output)
cmd.Wait()
func ConvertByte2String(byte []byte, charset Charset) string
var str string
switch charset
case GB18030:
var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
str = string(decodeBytes)
case UTF8:
fallthrough
default:
str = string(byte)
return str
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testcmd> go run .\\main.go
<nil>
正在 Ping www.a.shifen.com [110.242.68.3] 具有 32 字节的数据:
来自 110.242.68.3 的回复: 字节=32 时间=56ms TTL=53
来自 110.242.68.3 的回复: 字节=32 时间=53ms TTL=53
110.242.68.3 的 Ping 统计信息:
数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 53ms,最长 = 56ms,平均 = 54ms
*/
生成随机数(官方示例)
package main
import (
"bytes"
"fmt"
"math/rand"
)
func main()
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
fmt.Println(b)
if err != nil
fmt.Println("error", err)
return
fmt.Println(bytes.Equal(b, make([]byte, c)))
/*
PS D:\\GoWork\\src\\go_course\\day04-20230312\\codes\\testrand> go run .\\main.go
[205 251 34 232 77 192 249 191 123 108]
false
*/
三阶段课程——Day05(模块系统:自定义模块内置模块第三方模块;npm与包:包管路工具常用命令package.json包的分类包加载机制全局包)
一、模块系统
1、模块化介绍
传统开发的问题
随着项目的扩大,然后代码就越来越庞大 ,如果没有很好的规划,后期维护非常复杂(甚至就维护不了)。
<script src="c.js"> <script src="b.js"> <script src="a.js">
传统的解决方式
我们可以用全局命名、也可以用闭包、也可以面向对象封装。这就造成了程序员随心所欲的封装,没有规矩(规范)
2、Commonjs规范
这个commonjs规范是node中特有的,就是约束node中的模块的。
Commonjs组成:
(1)如何定义数据和功能函数(即如何定义公共代码)
(2)外部如何使用定义的数据和功能函数
定义规范的好处
既然是规范,那么就应该是大家默认都应该遵守的,这样就降低了沟通的成本,极大方便了各个模块之间的相互调用,利于团队协作开发。
3、模块的种类
- 自定义模块:(开发者自己定义的模块,每一个js文件都可以称为一个模块)
- 开发者,可以使用commonjs规范自己写的js文件,都称为自定义模块
- 内置模块:(由Node.js官方提供,如:fs、path、querystring等)
- 第三方模块:(由第三方开源出来的模块,使用前需要npm工具从npm社区下载)
- 第三方(可以是个人、也可以是一个小团队、也可以是公司)
4、自定义模块
介绍:开发者,遵守commonjs规范自己写的js文件,都称为自定义模块
使用步骤:
module:模块 exports:出口 require:要求
1、创建模块文件
2、在模块文件定义公共数据
3、把数据暴露出去
用moudule.exports或exports进行暴露
4、在某些文件中要使用这引用数据(引入:require)
自定义模块引入必须以.或..开头,这是commonjs规定
module.exports暴露
module/a.js 定义数据
// 定义数据 let name = \'zs\'; let sex = \'男\'; let age = 3; let obj = { fn() { console.log(\'前端开发\'); } } // 暴露出去 module.exports = { name, sex, age, obj }
let o = require(\'./module1/a.js\'); // 引入自定义模块,必须以.或..开头 // 使用 console.log(o); console.log(o.name); console.log(o.age); o.obj.fn();
原生模拟module.exports和exports的区别
// 直接给exports赋值,没有切断和module.exports的引用关系 function fn1() { let module = {}; module.exports = {}; let exports = module.exports; exports.a = 10; exports.b = 20; return module.exports; } console.log(fn1()); // {a:10, b:20} // ------------------------------ // 直接给module.exports赋对象,切断了和exports的引用关系 function fn2() { let module = {}; module.exports = {}; let exports = module.exports; module.exports = { // 用一个新的对象赋值,则切断了和原对象的引用关系 c: 3, d: 4 } return module.exports; } console.log(fn2()); // {c:3, d:4} // ---------------------------------- // module.exports和exports混用,因为给module.exports赋了对象,因此,exports赋的属性外面就没有 function fn3() { let module = {}; module.exports = {}; let exports = module.exports; module.exports = { c: 3 } exports.ab = 55; return module.exports; } console.log(fn3()); // {c:3} // ---------------------------- // 混用直接改属性,没有赋值,所以它们的引用关系存在 function fn4() { let module = {}; module.exports = {}; let exports = module.exports; module.exports.c = 3; exports.ab = 55; return module.exports; } console.log(fn4()); // {c:3, ab:55}
module.exports和exports的区别
module.exports和exports它们俩指向同一个对象,但是默认返回的是module.exports,所以可以对module.exports直接赋一个对象,但是如果直接给exports赋一个对象,则不可以。
总结:
- module.exports可以赋对象,也可以改属性。但是一旦赋了对象,则和exports的引用关系就没有了。加给exports的属性也没有了。
- exports只能改属性,不能赋对象,因为一赋对象,就切断了和module.exports的引用关系。
注意:这两个不要混用
js模块私有化
node的commonjs规范,把我们js模块都进行私有化了(不会污染全局变量):每一个js中的代码都套了一层匿名函数
a.js引用b.js文件,其实b就是一个模块,则b文件的外面,套了一个匿名的函数
通过在b中打印console.log(arguments.callee.toString())可以看出来
function (exports, require, module, __filename, __dirname) {
console.log(arguments.callee.toString());
}
面试中关于node底层的问题可能会问
练习
定义一个名为trim.js文件 暴露一个Trim方法。 Trim() //去除左右空格 Trim.left() //去除左空格 Trim.right() //去除右空格
trim.js
function Trim(str) { let re = /^\\s+|\\s+$/g; return str.replace(re, \'\'); } Trim.left = function (str) { let re = /^\\s+/; return str.replace(re, \'\'); } Trim.right = function (str) { let re = /\\s+$/; return str.replace(re, \'\'); } // 以下三种暴露方式均可 module.exports.Trim = Trim; // exports.Trim = Trim; // module.exports = { // Trim // }
let t = require(\'./trim.js\'); // console.log(t); let str = \' 小王吃饭了 \'; console.log(\'(\' + t.Trim(str) + \')\'); console.log(\'(\' + t.Trim.left(str) + \')\'); console.log(\'(\' + t.Trim.right(str) + \')\');
5、内置(核心)模块
fs / url / querystring / path
URL(了解)
简单的说就是网址。这个模块比较特殊,不需要引入(但要new实例化),类似于全局变量的用法 。
const myurl = \'http://www.ujiuye.com:8080/a/b/c?name=zs&age=3\' let u = new URL( myurl ) console.log( u ); console.log( u.searchParams.get(\'name\') ) console.log( u.searchParams.get(\'age\') ) console.log( u.pathname )
querystring(了解)
先引入模块,如果内置模块需要引入,则只写字符串名称即可。
类似于JSON.parse()和JSON.stringify()
const qs = require(\'querystring\') // qs.parse() // 把 "name=swk&age=20" 字符串 转成对象 // qs.stringify() // 把xxx对象 转成字符串 let d = { username:\'swk2\', age:30 }
path(掌握)
parse解析, basename文件名, extname后缀名, join拼接
const filepath = \'a/b/c/d/a.html\'; // 解析路径,包含文件名,后缀名等等 // let o = path.parse(filepath); // console.log(o); // --------------------------- // 文件名和后缀名 // console.log(path.basename(filepath)); // 完整的文件名 // console.log(path.extname(filepath)); // 后缀名 // ------------------------------ // 路径拼接 console.log(__dirname); // D:\\0524\\day05\\1代码\\demo4 let url = path.join(__dirname, \'./demo/a.txt\'); // 路径拼接 console.log(url); // \'D:\\0524\\day05\\1代码\\demo4\\demo\\a.txt\'
6、第三方模块
第三方模块又可以称为包
包的方法
假如你的业务中需要处理字符串,字符串需要去除空格(trim)或处理时间(time-stamp)
其实就是没有必要去造轮子,而很多现成的公共代码已经封装好了(使用commonjs规范)
1、建立你自己的业务代码
2、在你业务代码下打开cmd,下载第三方模块(包) npm i 包名
npm install trim
下载完成之后,你的项目根目录下会有一个node_modules
文件夹和package-lock.json
文件
3、在自己的业务文件中引入第三方模块(包)
let t = require( 第三方模块名称 )
4、根据业务写代码
二、npm与包
1、包的概念
包:Node.js中的第三方模块又叫做包。就像电脑和计算机指的是同一个事物,第三方模块和包指的是同一个概念,只不过叫法不同。
npm:主要内容分为两块:(1)包管理工具 (2)npm社区
包来源:
包是由第三方个人或团队开发出来的,免费供给所有开发者使用。
npm社区:https://www.npmjs.com/
包的特点:
-
-
包是基于内置模块( 按照commonjs规范 ) 封装出来的,提供了更高级、更方便的API,极大的提高了开发效率
-
包和模块之间的关系,类似于Jquery和原生js之间的关系
-
2、包管理工具npm
包管理工具指的是安装node环境后,自动安装了npm工具。全称(Node Package Manager),简称 npm 包管理工具。
查看安装的版本 npm -v
第一次安装包的说明
-
-
node_modules文件夹用来存放所有已安装到项目中的第三方包。require()导入第三方包时,就是从这个目录中查找并加载
-
package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等
-
3、常用命令
init:项目初始化
npm init
npm init [-y]
install/i:安装包
npm install/i 包名 默认下载最新的版本 npm install/i 包名@版本号 下载特定的版本包 npm install trim@1.0.0 注意:只能保留一个版本 npm install/i 包名 -D/--save-dev 开发依赖 npm install/i 包名 -S/--save 项目依赖 npm install 包名1 包名2 ... 一次安装多个包
uninstall/r:卸载包
npm uninstall 包名
npm r 包名
4、查看手册
5、package.json
工作中给别人项目时,是不给node_modules的,应该使用git,通过.gitignore把node_modules给忽略掉
需要包含name,version,main等信息,如下表
属性名 | 说明 |
---|---|
name | 包(项目)的名称 |
version | 包(项目)的版本号 |
description | 包(项目)的描述 |
main | 包(项目)入口文件 |
scripts(到项目中可以讲到) | 定义快捷脚本命令 |
keywords | 项目关键词 |
author | 作者 |
license | 协议 |
dependencies | 包(项目)依赖的模块 |
devDependencies( webpack再说 ) | 包(项目)开发依赖的模块 |
重要属性
dependencies 项目依赖
会自动的记录到dependencies属性中 npm i 包名 npm i 包名 -S npm i 包名 --save
devDenpendencies 开发依赖
会自动的记录到devDependencies属性中 npm i 包名 -D npm i 包名 --save-dev
使用命令创建package.json文件
npm init [-y] : 默认配置直接生成package.json文件。
注意事项:文件夹不要有中文,不要使用第三方模块名称和内置模块的名称定义项目文件夹名
npm init : 一问一答的形式(不推荐)
6、包的分类
项目包
被安装到项目的node_modules目录中的包,都是项目包
项目包又分为两类
1)开发依赖包:被记录到devDenpendencies节点中的包,只在开发期间会用到(只是在写代码的时候用)
2)核心依赖包:被记录到dependencies节点中的包,在开发期间和项目上线之后都会用到。
总结:我们的包会很多很多,只记录你自己下载的包即可(但是也不用刻意记,因为常用的就那么几个,而且package.json帮我们记录了)
全局包
markdown工具包
npm地址:https://www.npmjs.com/package/markdown
npm i markdown -g
命令行:
md2html 笔记06.md > abc.html
7、包加载机制(总结)
内置模块的加载机制
内置模块是由Node.js官方提供的模块,内置模块的加载优先级最高。例如,require(\'fs\') 始终返回内置的fs模块,即使在node_modules目录下有名字相同的包也叫做fs,也会引入核心的内置fs模块。
所以第三方模块(npm上搜索不到内置模块)和自定义模块不要起官网已有的模块名称。
官方给的建议:自己定义模块的时候,不要起官方的内置模块 。
注意:在引入内置模块的时候不要 加 .和..( fs、path、querystring、url )
// let fs = require(\'fs\'); // 引入内置的 // console.log(fs); let fs = require(\'./node_modules/fs/index\'); // 引入自己的,不要这样做(自定义模块不要放在node_modules中) console.log(fs);
自定义模块加载机制
1)使用require()加载自定义模块时,必须指定以./或../开头的路径标识符。
2)如果没有指定./或../这样的路径标识符,则Node.js会把它当作内置模块或第三方模块进行加载。
3)自定义模块不要放在node_modules中。
4)在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:
(1)文件名.js扩展名进行加载
(2)文件名.json扩展名进行加载
json文件中必须是以 [] 或 {} 包起来的数据,键必须是双引号、如果你对应的值是字符串则必须带双引号
(3)加载失败,终端报错Error:Cannot find module \'xxx\'
//1. 完整的写法 // let t = require(\'./module/t1.js\')// //2. 后缀名可以省略,按照 .js 和 .json的顺序进行加载。 //如果没有则报错 xxx not find // let t = require(\'./module/t1\') //let t = require(\'./module/t2\') //let t = require(\'./module/t2\') let t = require(\'./module/t3\') // cantnot find \'t3.js\' console.log(t );
第三方模块加载机制
1)如果require()的模块标识符不是内置模块,即没有以‘./’或‘../’开头,则Node.js会从当前模块的父目录开始,尝试从当前文件夹的/node_modules文件夹中加载第三方模块。
2)如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到当前项目文件的盘符根目录。
总结:一定是把第三方模块下载到 根项目下的 node_modules ,且项目中只有根项目下有 node_modules
package.json中的main属性
main属性,可以指定模块加载的主入口文件,当引入模块时用文件夹名结尾时生效。有三种加载方式:
1)根据目录下的package.json的文件,寻找main属性指定的文件名,作为require()加载的入口。
2)如果目录里没有package.json文件,或者main入口不存在,则Node.js将会加载目录下的index.js文件(所以目录中的默认入口为index.js)。
3)如果以上两步都加载失败,则Node.js会在终端打印错误消息,报告模块缺失:Error:Cannot find module \'xxx\'
8、全局包
项目包:之前学所的是项目包,是在我们js文件中需要 require 引入的。
全局包:又称 “工具”,不是写代码。
需求:把.md文件 转换成 html。
比如:markdown的全局的使用规则 。
1、下载 g == global
只需要下载一次,无论哪个目录都可以执行此命令
npm i 包名 -g npm i markdown -g 虽然包名叫markdown,但是实际下载下来的文件名叫 md2html / md to html
2、下载到此目录
C:\\Users\\你的用户名\\AppData\\Roaming\\npm
3、而是当作命令来使用的
md2html 笔记06.md > 06.html
以上是关于阶段1 Go语言基础Day04 包管理 常用模块 单元测试的主要内容,如果未能解决你的问题,请参考以下文章
三阶段课程——Day05(模块系统:自定义模块内置模块第三方模块;npm与包:包管路工具常用命令package.json包的分类包加载机制全局包)
阶段1 Go语言基础Day02 数组切片切片原理map字符串处理/字节切片排序