阶段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、模块化介绍

  传统开发的问题

  随着项目的扩大,然后代码就越来越庞大 ,如果没有很好的规划,后期维护非常复杂(甚至就维护不了)。

  比如:前端html中有很多特效会依赖文件:a.js、b.js、c.js、....

<script src="c.js">
<script src="b.js">
<script src="a.js">

  

  传统的解决方式

  我们可以用全局命名、也可以用闭包、也可以面向对象封装。这就造成了程序员随心所欲的封装,没有规矩(规范)

  node中提出了模块的概念。把公共的函数(代码)进行模块化封装(那么一定是有要求的【规范】)。

 

  解决问题(好处)

    1、有规范

    2、代码复用高

    3、易维护

 

  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
}

 

 

  1 自定义模块.js使用

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/

 

  包的特点:

  • 在Node.js中,如果只用内置模块或开发者自己定义模块开发,效率会很低。所以就有了第三方包

  • 包是基于内置模块( 按照commonjs规范 ) 封装出来的,提供了更高级、更方便的API,极大的提高了开发效率

  • 包和模块之间的关系,类似于Jquery和原生js之间的关系

  • 要想称为一个包除了遵守模块化规范以外,还要遵守包的一些规范,如:说明文档,协议说明等。

 

  2、包管理工具npm

  包管理工具指的是安装node环境后,自动安装了npm工具。全称(Node Package Manager),简称 npm 包管理工具。

  查看安装的版本 npm -v

 

  第一次安装包的说明

  • 初次装包完成后,在项目文件夹下多一个node_modules的文件夹和package-lock.json的配置文件

  • node_modules文件夹用来存放所有已安装到项目中的第三方包require()导入第三方包时,就是从这个目录中查找并加载

  • package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等

  • 开发者不要手动修改node_modules或package-lock.json文件中的任何代码,npm包管理工具会自动维护它们

 

  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、查看手册

  以trim为例:https://www.npmjs.com/package/trim

 

 

  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字符串处理/字节切片排序

Go常用功能总结一阶段

GO语言常用标准库03---time包

Python自动化开发课堂笔记Day04 - Python基础(函数补充,模块,包)

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