当前位置: 首页 > news >正文

单页面营销型网站制作市场营销实务

单页面营销型网站制作,市场营销实务,世界上让导航崩溃的城市,wordpress好学1. 系统命令调用 所谓的命令调用#xff0c;就是通过os#xff0c;找到系统中编译好的可执行文件#xff0c;然后加载到内存中#xff0c;变成进程。 1.1 exec.LookPath#xff08;寻找命令#xff09; 作用#xff1a; exec.LookPath 函数用于在系统的环境变量中搜索可…1. 系统命令调用 所谓的命令调用就是通过os找到系统中编译好的可执行文件然后加载到内存中变成进程。 1.1 exec.LookPath寻找命令 作用         exec.LookPath 函数用于在系统的环境变量中搜索可执行文件的路径。这个函数属于 os/exec 包通常用于查找并执行系统命令。 语法         func exec.LookPath(file string) (string, error) 参数         file string要查找的可执行文件的名称。 返回值         string该返回值是可执行文件的完整路径如果找到了的话。         error该返回值是一个错误对象如果搜索过程中出现错误则返回非 nil 值。 package mainimport (fmtos/exec )func main() {// 通过LookPath在系统PATH中找命令s, err : exec.LookPath(git)if err ! nil {panic(err)} else {fmt.Println(命令在path中找到)} } 调试结果 命令在path中找到 1.2 exec.Command构造要执行的命令 作用         exec.Command 函数用于创建一个要执行的命令的 *exec.Cmd 结构体但并不执行。 语法         func exec.Command(name string, arg ...string) *exec.Cmd 参数         name string要执行的可执行文件的名称。如果该文件不在系统的 PATH 环境变量中你需要提供完整的路径。         arg ...string一个字符串切片表示传递给命令的参数。第一个参数通常是子命令或命令的主要用途后续参数是该命令的其他选项或参数。 返回值         *exec.Cmd返回一个 *exec.Cmd 结构体它表示要执行的命令。 package mainimport (fmtos/exec )func main() {// 通过LookPath在系统PATH中找命令s, err : exec.LookPath(git)if err ! nil {panic(err)}// 构造要执行的命令// c : exec.Command(s, -v) // git -v// 或者还可以这样c : exec.Command(s, []string{-v}...)fmt.Println(c) // 打印执行的命令fmt.Println(c.Args) // 打印命令的参数列表 } 调试结果 D:\软件安装\Git\Git\cmd\git.exe -v [D:\软件安装\Git\Git\cmd\git.exe -v] 1.3 Output执行命令并输出结果 作用         Output 方法用于执行命令并捕获其标准输出。这个方法会启动命令等待命令完成并返回命令的输出。 语法         func (*exec.Cmd).Output() ([]byte, error) 返回值         []byte输出结果。         error如果执行过程中遇到错误会返回错误信息。 package mainimport (fmtos/exec )func main() {// 通过LookPath在系统PATH中找命令s, err : exec.LookPath(git)if err ! nil {panic(err)}// 构造要执行的命令c : exec.Command(s, -v) // git -v// 或者还可以这样// c : exec.Command(s, []string{-v}...)fmt.Println(c) // 打印执行的命令fmt.Println(c.Args) // 打印命令的参数列表// 执行命令并输出结果b, err2 : c.Output()if err2 ! nil {panic(err2)}fmt.Println(b)fmt.Printf(b%v\nstring(b)%v, b, string(b)) } 调试结果 D:\软件安装\Git\Git\cmd\git.exe -v [D:\软件安装\Git\Git\cmd\git.exe -v] [103 105 116 32 118 101 114 115 105 111 110 32 50 46 52 52 46 48 46 119 105 110 100 111 119 115 46 49 10] b[103 105 116 32 118 101 114 115 105 111 110 32 50 46 52 52 46 48 46 119 105 110 100 111 119 115 46 49 10] string(b)git version 2.44.0.windows.1 2. 日志 2.1 log包 Go标准库中有log包提供了简单的日志功能。 日志输出需要使用日志记录器Logger。 2.1.1 log.Print 作用         输出日志信息。 语法         func log.Print(v ...any) 参数         v ...any表示接受任意数量的参数并且每个参数可以是任何类型多参数用逗号分隔。 package mainimport (fmtlog )func main() {log.Print(xxxxx)fmt.Println(xxxx) } 这里在ide看的比较明显log.Print默认打印出来的是含年月日时分秒的且是红色字体这是因为它用的是stderr标准错误输出。 而fmt.Print是标准输出stdout所以是蓝色字体。 但是颜色仅仅在ide有显示编译后执行或linux系统中是无颜色的。 2.1.2 log.Fatal 作用         用于输出日志信息并且在输出日志信息后会调用 os.Exit(1) 来终止程序的运行。 语法         func log.Fatal(v ...any) 参数         v ...any任意数量任意类型的参数多个参数用逗号分隔。 2.1.3 log.Panic 作用         用于输出日志信息并在输出后触发一个 panic这会导致程序立即停止运行并开始 panic 恢复机制。 语法         func log.Panic(v ...any) 参数同上。 package mainimport (log )func main() {log.Panic(log.Panic test!!!) } 2.2 log.Print系列源码讲解 2.2.1 日志记录器Logger var std New(os.Stderr, , LstdFlags)注意这个std虽然是个全局变量但小写包外不可见的。 上面我们用的log.Print系列都是调用的这个std对象但该std既不是标准输出也不是标准错误输出而是一个标准logger。 因为日志的输出是需要使用日志记录器Logger的通过Logger才能输出日志并不是直接print就行了。 Logger日志记录器也叫缺省日志记录器。 var std New(os.Stderr, , LstdFlags)含义 1New这是 log 包中的一个函数用于创建一个新的 log.Logger 对象logger实际是一个结构体。 2os.Stderr这是标准库 os 包中的一个变量表示标准错误输出stderr。日志信息会被输出到这个标准错误流。 3这是 New 函数的第二个参数表示日志消息前缀。这里传入空字符串意味着日志消息前不会有额外的前缀。 4LstdFlags这是 log 包中定义的一组日志标志位用于控制日志输出的格式。LstdFlags 通常包括时间戳、日志级别等信息。 这里注意LstdFlags点击它看下源码 const (// 将日志的日期设置为当地时间格式为 2009/01/23。这是通过左移操作符和 iota 关键字实现Ldate 1 iota // the date in the local time zone: 2009/01/23// 将日志的时间设置为当地时间格式为 01:23:23。Ltime // the time in the local time zone: 01:23:23// 在时间中包含微秒格式为 01:23:23.123123,这个选项假设 Ltime 已经被设置。Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.// 在日志中包含完整的文件名和行号例如 /a/b/c/d.go:23。Llongfile // full file name and line number: /a/b/c/d.go:23// 在日志中包含文件名的最后一个元素和行号例如 d.go:23。如果设置了这个选项它会覆盖 Llongfile。Lshortfile // final file name element and line number: d.go:23. overrides Llongfile// 如果设置了 Ldate 或 Ltime使用协调世界时UTC而不是本地时区。LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone// 将日志前缀从行的开始移动到消息之前。Lmsgprefix // move the prefix from the beginning of the line to before the message// 是一个组合标志设置了日志的初始值这里组合了 Ldate 和 Ltime。LstdFlags Ldate | Ltime // initial values for the standard logger ) 上表列出的方法底层都使用std.Output输出日志内容。而std本质上是使用了标准错误输出、无前缀、 LstdFlags标准标记的记录器Logger实例。 2.3 std(标准输出)使用 package mainimport (log )func main() {log.Print(log.Print)log.Printf(log.Printf)log.Println(log.Println)// 等价于log.Print(log.Fatal);os.Exit(1)log.Fatal(log.Fatal)// 等价于log.Println(xxx); panic()panic的退出状态码为2log.Panicln(log.Panicln) } 调试结果 2024/09/29 11:44:14 log.Print 2024/09/29 11:44:14 log.Printf 2024/09/29 11:44:14 log.Println 2024/09/29 11:44:14 log.Fatal 2.4 自定义Logger 2.4.1 标准输出 package mainimport (logos )func main() {// stdout: 标准输出logger : log.New(os.Stdout, , log.LstdFlags)logger.Println(这是自定义的标准日志输出) } 调试结果 2024/09/29 13:56:22 这是自定义的标准日志输出 2.4.2 标准错误输出 package mainimport (logos )func main() {// stderr: 标准错误输出// log.LstdFlags: 年月日时分秒// log.Lshortfile在日志中包含完整的文件名和行号logger1 : log.New(os.Stderr, 日志前缀, log.LstdFlags|log.Lshortfile)// Fatalln: Printlnos.Exit(1)logger1.Fatalln(自定义的标准错误输出。) } 调试结果 日志前缀2024/09/29 14:03:21 main.go:15: 自定义的标准错误输出。 Process 3312 has exited with status 1 这里注意两个地方 1日志前缀2024/09/29 14:03:21 main.go:15: 自定义的标准错误输出。 这里明确的显示了错误的地方在main.go:15。 2status 1 退出状态码为1。 然后还可以配置flag调整日志前缀的位置。 package mainimport (logos )func main() {// stderr: 标准错误输出// log.LstdFlags: 年月日时分秒// log.Lshortfile在日志中包含完整的文件名和行号logger1 : log.New(os.Stderr, 日志前缀, log.LstdFlags|log.Lshortfile)// Fatalln: Printlnos.Exit(1)logger1.Println(自定义的标准错误输出。)logger2 : log.New(os.Stderr, 日志前缀, log.LstdFlags|log.Lshortfile|log.Lmsgprefix)logger2.Fatalln(自定义的标准错误输出。) } 调试结果 日志前缀2024/09/29 14:23:42 main.go:15: 自定义的标准错误输出。 2024/09/29 14:23:42 main.go:18: 日志前缀自定义的标准错误输出。 2.5 日志持久化 package mainimport (logos )func main() {logfile : D:/个人/学习/Go/文件与目录操作/test.logf, err : os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, os.ModePerm)if err ! nil {log.Panic(err)}defer f.Close()l : log.New(f, , log.LstdFlags|log.Lshortfile)l.Println(日志持久化文件测试!) }3. zerolog 官网https://zerolog.io/ 上面介绍的log模块太简陋了实际使用并不方便。   常用的三方日志模块如下 1logrus有日志级别、Hook机制、日志格式输出很好用。 2zap是Uber的开源高性能日志库。 3zerolog更注重开发体验高性能、有日志级别、链式APIjson格式日志记录号称0内存分配。 3.1 下载 go get -u github.com/rs/zerolog/log 3.2 简单日志示例 对于简单的日志记录导入全局记录器包github.com/rs/zerolog/log package main// 注意这个包的自动引入的话需要先zerolog等import github.com/rs/zerolog出来后再自动补充后面的/log import github.com/rs/zerolog/logfunc main() {log.Print(zerolog/log Print test)log.Fatal().Msg(zerolog/log Fatal test)// 这个也是 os.Exit(1) } 调试结果 {level:debug,time:2024-09-29T17:28:0908:00,message:zerolog/log Print test} {level:fatal,time:2024-09-29T17:28:0908:00,message:zerolog/log Fatal test} 3.3 日志级别 zerolog提供以下级别从高到底 panic (zerolog.PanicLevel, 5)fatal (zerolog.FatalLevel, 4)error (zerolog.ErrorLevel, 3)warn (zerolog.WarnLevel, 2)info (zerolog.InfoLevel, 1)debug (zerolog.DebugLevel, 0)trace (zerolog.TraceLevel, -1) 且级别还分为 gLevel全局级别。 zerolog.SetGlobalLevel(级别数字或常量) 来设置全局级别。 zerolog.GlobalLevel() 获取当前全局级别。每个Logger的级别日志记录器级别。消息的级别Msg。 package mainimport (github.com/rs/zerolog/log )func main() {// debug级别的消息相当于log.Debug().Msg()log.Print(zerolog/log Print test)// fatal级别的消息结合了os.Exit(1)log.Fatal().Msg(zerolog/log Fatal test)// Panic级别的消息log.Panic().Msg(zerolog/log Panic test) }3.3.1 尝试先理解“级别” 首先是我们使用的Zeerolog包中的log.xxx这种它其实是一个缺省默认的的logger比如log.Print点这个Print看下源码 func Print(v ...interface{}) {Logger.Debug().CallerSkipFrame(1).Msg(fmt.Sprint(v...)) } 然后再点击Logger跳转到下一层源码 var Logger zerolog.New(os.Stderr).With().Timestamp().Logger() 可以看到这里定义了一个全局的且包外可见的Logger我们之前使用的zerrolog包中的log.xxx实际调用的都是这个缺省Logger。 我们可以尝试着调用一下这个Logger package mainimport (fmtgithub.com/rs/zerolog/log )func main() {fmt.Println(log.Logger) } 调试结果 {{0xc00000a020} -1 nil [123] [{}] false nil}可以看到log.Logger缺省logger的默认级别为 -1 trace。 那可以尝试自定义一下这个默认的Logger日志记录器级别 package mainimport (fmtgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {fmt.Println(log.Logger)// 自定义Logger级别记录器级别log1 : log.Logger.Level(zerolog.InfoLevel)fmt.Println(log1)} 调试结果 {{0xc00000a020} -1 nil [123] [{}] false nil} {{0xc00000a020} 1 nil [123] [{}] false nil} 可以看到上面自定义的级别已经从原来的-1变成1了。 接下来试试-1和1在一起打印。 package mainimport (fmtgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {fmt.Println(log.Logger)// 自定义Logger级别记录器级别log1 : log.Logger.Level(zerolog.InfoLevel)fmt.Println(log1)log.Debug().Msg(log.Debug相当于是log.Print) // 缺省logger// 这一条不会打印// 该消息是debug级别通过log1这个日志记录器输出log1.Debug().Msg(自定义日志级别的logger) } 调试结果 {{0xc00000a020} -1 nil [123] [{}] false nil} {{0xc00000a020} 1 nil [123] [{}] false nil} {level:debug,time:2024-09-30T15:10:1508:00,message:log.Debug相当于是log.Print}为什么log1.Debug().Msg(自定义日志级别的logger)没有打印 这里就涉及到另一个级别了“消息级别”。 级别分为“记录器级别”和“消息级别Logger”我们使用log.xxx输出的都是“消息级别”那为啥上面的log1没有打印出来呢 输出成功的前提消息级别必须 日志记录器级别。 我们在log1中自定义的级别是记录器级别记录器级别为info但log1的消息级别为debug所以输出不了。 所以这里尝设置log1的消息级别为Info这样消息级别和记录器级别就相等了。 package mainimport (fmtgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {fmt.Println(log.Logger)// 自定义记录器日志级别log1 : log.Logger.Level(zerolog.InfoLevel)fmt.Println(log1)// 缺省logger的消息级别为debuglog.Debug().Msg(log.Debug相当于是log.Print)// 这一条不会打印因为log1的记录器日志级别为Infolog1.Debug().Msg(自定义日志级别的logger)log1.Info().Msg(调整log1的消息级别为Info) } 调试结果 {{0xc00000a020} -1 nil [123] [{}] false nil} {{0xc00000a020} 1 nil [123] [{}] false nil} {level:debug,time:2024-09-30T15:41:3608:00,message:log.Debug相当于是log.Print} {level:info,time:2024-09-30T15:41:3608:00,message:调整log1的消息级别为Info} 可以看到调整log1消息级别为Info后终于输出了。 3.3.2 zerolog package mainimport (fmtgithub.com/rs/zerolog )func main() {fmt.Println(zerolog.GlobalLevel()) } 调试结果 trace 可以看到zerolog默认的级别为trace也就是-1。 调整默认级别 package mainimport (fmtgithub.com/rs/zerolog )func main() {// 3 Errorzerolog.SetGlobalLevel(zerolog.ErrorLevel)fmt.Println(zerolog.GlobalLevel()) } 调试结果 error 然后我们结合之前的代码 package mainimport (fmtgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {// 3 Errorzerolog.SetGlobalLevel(zerolog.ErrorLevel)fmt.Println(zerolog.GlobalLevel())fmt.Println(log.Logger)log1 : log.Logger.Level(zerolog.InfoLevel)fmt.Println(log1)log.Debug().Msg(log.Debug相当于是log.Print)log1.Debug().Msg(自定义日志级别的logger)log1.Info().Msg(调整log1的消息级别为Info)log1.Error().Msg(调整log1的消息级别为Error) } 调试结果 error {{0xc00000a020} -1 nil [123] [{}] false nil} {{0xc00000a020} 1 nil [123] [{}] false nil} {level:error,time:2024-09-30T17:02:2108:00,message:调整log1的消息级别为Error} 根据上述代码发现zerolog.SetGlobalLevel(zerolog.ErrorLevel)后原来log和log1的debug和info级别的消息都不打印了只有log1的error级别打印。 这说明SetGlobalLevel控制所有Logger的输出级别只有GlobalLevel的消息级别才能输出。 那也就是说消息级别 MAX(Logger记录器, GlobalLevel)才能最终输出。 3.3.3  消息与日志记录器 首先消息需要通过日志记录器才能输出不管是输出到屏幕还是文件。   如log1.Info().Msg()。 消息Msg()是Info级别Info()的通过log1这个日志记录器输出。 但消息输出的前提消息级别 MAX(Logger记录器此处是log1自己, GlobalLevel)才能最终输出。 3.4 上下文 zerolog是以Json对象格式输出的还可以自定义一些键值对字段增加到上下文中以输出。 3.4.1 自定义字段  package mainimport (github.com/rs/zerologgithub.com/rs/zerolog/log )func main() {zerolog.SetGlobalLevel(zerolog.InfoLevel)log.Info().Msg() } 调试结果 {level:info,time:2024-10-08T11:45:2508:00} 从上面的输出可以看到Msg为空实际打印出来的消息体中也没有mssage。 那我们尝试着自定义一下 package mainimport (github.com/rs/zerologgithub.com/rs/zerolog/log )func main() {zerolog.SetGlobalLevel(zerolog.InfoLevel)log.Info().Str(School, magedu.com).Msg()log.Info().Str(School, magedu.com).Bool(Address, true).Msg() } 调试结果 {level:info,School:magedu.com,time:2024-10-08T14:31:3408:00} {level:info,School:magedu.com,Address:true,time:2024-10-08T14:31:3408:00} 可以看到可以通过Str来自定义内容且Str可以多个还可以使用其他数据类型。 3.5 错误日志 package mainimport (errorsgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {zerolog.SetGlobalLevel(zerolog.InfoLevel)err : errors.New(test error)log.Error().Msg(err.Error())log.Error().Err(err).Msg()log.Error().Err(err).Send()log.Fatal().Err(err).Send()log.Panic().Err(err).Send() } 调试结果 {level:error,time:2024-10-09T10:29:5908:00,message:test error} {level:error,error:test error,time:2024-10-09T10:29:5908:00} {level:error,error:test error,time:2024-10-09T10:29:5908:00} {level:fatal,error:test error,time:2024-10-09T10:29:5908:00} package mainimport (errorsgithub.com/rs/zerologgithub.com/rs/zerolog/log // 全局logger )func main() {zerolog.TimeFieldFormat zerolog.TimeFormatUnix // 自定义time字段时间的格式TimeFormatUnix时间戳// zerolog.ErrorFieldName err // 修改日志Json中的缺省字段名error// 错误日志err : errors.New(自定义的错误)log.Error(). // 错误级别消息Err(err). // err字段错误消息内容Send() // 有错误消息了message可以省略log.Fatal(). // fatal级别Err(err).Send() }3.6 自定义全局logger 3.6.1 全局logger // Logger is the global logger. var Logger zerolog.New(os.Stderr).With().Timestamp().Logger() 默认使用是这样的 package mainimport (github.com/rs/zerolog/log )func main() {log.Debug().Msg(debug)log.Error().Msg(Error) } 调试结果 {level:debug,time:2024-10-09T10:44:3308:00,message:debug} {level:error,time:2024-10-09T10:44:3308:00,message:Error} 3.6.2自定义全局Logger 不建议直接修改默认的全局logger如果有需求最好自定义一个。 package mainimport (github.com/rs/zerolog/log )func main() {log.Logger log.With().Str(School, haha).Logger()log.Debug().Msg(debug)log.Error().Msg(Error) } 调试结果 {level:debug,School:haha,time:2024-10-09T10:46:1108:00,message:debug} {level:error,School:haha,time:2024-10-09T10:46:1108:00,message:Error} package mainimport (github.com/rs/zerologgithub.com/rs/zerolog/log )func main() {zerolog.TimeFieldFormat zerolog.TimeFormatUnixlogger : log.With(). // With()返回基于全局Logger的子loggerStr(School, Magedu).Caller(). // 增加日志调用的位置信息字段Logger() // 返回Loggerlogger.Info().Send() // {level:info,School:Magedu,time:1223947070}log.Info().Send() // {level:info,time:1223947070} 全局Logger }package mainimport (fmtosgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {zerolog.TimeFieldFormat zerolog.TimeFormatUnixlogger : zerolog.New(os.Stdout). // 不基于全局Logger重新构造了一个LoggerWith().Str(School, Magedu).Caller(). // 调用者信息增加日志函数调用的位置信息字段Logger(). // 返回LoggerLevel(zerolog.ErrorLevel) // 重新定义Logger级别为3 error返回Loggerfmt.Println(logger.GetLevel())logger.Info().Send() // {level:info,School:Magedu,time:1223947070}看颜色区别logger.Error().Send()log.Info().Send() // {level:info,time:1223947070} 全局Logger }3.7 写入日志文件 3.7.1 只写入文件 package mainimport (fmtosgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {f, err : os.OpenFile(D:/个人/学习/Go/文件与目录操作/test.log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm)if err ! nil {log.Panic().Err(err).Send()}defer f.Close()log1 : zerolog.New(f)log1.Info().Msg(测试写入) }3.7.2 写入文件并输出到控制台 package mainimport (osgithub.com/rs/zerologgithub.com/rs/zerolog/log )func main() {f, err : os.OpenFile(D:/个人/学习/Go/文件与目录操作/test.log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm)if err ! nil {log.Panic().Err(err).Send()}defer f.Close()// log1 : zerolog.New(f)// log1.Info().Msg(测试写入)// 一分为二一边写文件一边控制台输出lw : zerolog.MultiLevelWriter(f, os.Stdout)log : zerolog.New(lw).With().Timestamp().Str(school, haha).Logger().Level(zerolog.InfoLevel)log.Info().Send() } 调试结果 {level:info,school:haha,time:2024-10-09T17:46:1708:00} 4. 包管理 用任何语言来开发如果软件规模扩大会编写大量的函数、结构体、接口等代码这些代码不可能写在一个文件中这就会产生大量的文件。 如果这些文件杂乱无章就会造成名称冲突、重复定义、难以检索、无法引用、共享不便、版本管理等一系列问题。 如有一些功能模块如何复用如何共享方便其他项目使用。 所以一定要有模块化包管理解决以上诸多问题。 4.1 包 包由多个文件和目录组成。使用 package 包名 来定义包名。包名一般都采用小写符合标识符要求。当前目录名和 package 包名 中的包名不需要一致但最好保持一致。同级文件归属一个包就是说每个包目录的当前目录中只能统一使用同一个package的包名否则编译出错。 一般来说开发项目时可以把相关功能的代码集中放在某个包里面例如在main包目录中新建一个calc包将所有计算函数都放在其中以供别的代码调用。   同一个目录就是同一个包该包内go文件里的变量、函数、结构体互相可见可以直接使用。   跨目录就是跨包使用时需要导入别的包导入需要指定该包的路径。 4.1.1 包内可见演示 先在main.go文件中定义2个全局变量 package main// 定义一个小写全局变量包内(main包内)可见 var a 100// 大写全局变量包外(main包外)可见 var B 200func main() {}再在main.go文件同级目录中创建一个x.go文件并调用a和B变量 package mainimport fmt// 这个test函数也属于包内可见函数如果首字母大写那就是包外可见 func test() {fmt.Println(a, B)// 因为该文件也是属于main包的所以可以调用aB变量 }回到main.go文件中调用test函数 package main// 定义一个小写全局变量包内(main包内)可见 var a 100// 大写全局变量包外(main包外)可见 var B 200func main() {test() } 调试结果 100 200 4.2 包管理的发展历程 4.2.1 GOPATH Go 1.11版本之前项目依赖包存于GOPATH。GOPATH是一个环境变量指向一个目录其中存放项 目依赖包的源码。 GOPATH默认值是 家目录/go 。 开发的代码放在 GOPATH/src 目录中编译这个目录的代码生成的二进制文件放到 GOPATH/bin 目录 下。 这会有以下问题 GOPATH不区分项目代码中任何import的路径均从GOPATH作为根目录开始。如果有多个项目不同项目依赖不同库的不同版本这就很难解决了。所有项目的依赖都放在GOPATH中很难知道当前项目的依赖项是哪些。 4.2.2 GOPATH vendor机制 Go1.5引入vendor机制。 vendor将项目依赖包复制到项目下的vendor目录在编译时使用项目下的vendor目录的包进行编译。 但依然不能解决不同项目依赖不同包版本问题。 该方式下的包搜索顺序 在当前包vendor目录查找向上级目录查找直到GOPATH/src/vendor目录 在GOPATH目录查找 在GOROOT目录查找标准库 4.2.3 Go Modules官方解决方案 Go Modules是从Go 1.11版本引入到1.13版本之后已经成熟Go Modules成为官方的依赖包管理解决方案。 优势 不受GOPATH限制代码可放在任意目录。自动管理和下载依赖且可以控制使用版本。不允许使用相对导入。 4.2.3.1 go modules 初始化 之前也演示过我们最开始写好代码后需要执行一段命令来初始化我们的代码 go mod init 自定义模块名 执行完后会在当前目录下生成一个go.mod文件且里面会包含我们使用的第三方库。这样每个目录都有自己的go.mod就不用担心冲突啥的。 如果想改模块名可以手动修改然后当前目录下所有文件都属于该模块。 5. Module模式 5.1 go mod命令 在Go1.11开始引入可以在任何目录使用go.mod创建项目。 go mod init name 命令在当前文件夹下初始化一个新的module, 创建go.mod文件。go mod tidy 命令自动分析依赖下载缺失的模块移除未使用的模块并更新go.mod文件。 5.1.1 go mod tidy演示 比如我下面这个代码引入了一些包 在go.mod中就是这样的 包括还有go.sum中也会生成内容 那如果我们不需要这些东西了该怎么办呢可以如下操作。 5.1.1.1 清理无用依赖 执行go mod tidy 5.1.1.2 恢复依赖 上面的报错是说这个包还在但是go.mod中没有所以没有办法使用。 解决办法如下 上面没有//indirect的是直接依赖有//indirect的是间接依赖就是直接依赖需要的依赖包。 5.2 导入子包 5.2.1 创建子目录和文件 package calc // 这个包名可以自定义但是建议和目录名一致。import fmt// 注意首字母大写才能包外可见 func Add(x, y int) int {fmt.Printf(这是calc.go里面打印的)return x y }这里注意同一级目录中的.go文件package名必须一致。 5.2.2 在main包中调用calc.go中的Add函数 package mainimport (// 注意这个test一定要是go.mod中的module nametest/calc )func main() {calc.Add(1, 2) } 调试结果 这是calc.go里面打印的 5.2.3 在子包中创建子包 在子目录中创建子目录和代码文件 5.2.4 调用子包中的子包 5.3 import导入包 5.3.1 绝对导入 就是下面这种包都是绝对路径的。 package mainimport (// 注意这个test一定要是go.mod中的module nametest/calctest/calc/minus ) 5.3.2 别名导入 如果有两个导入的包冲突时可以重命名包来避免冲突 import m magedu.com/tools/calc/minus// 使用举例 m.Minus() 5.3.3 相对导入 不建议使用 import ./calc5.3.4 匿名导入 import _ magedu.com/tools/calc/minus 使用下划线作为别名就意味着无法使用了那其目的何在 这种情况下只能执行导入的包内的所有init函数了。主要作用是做包的初始化用。 5.4 导入本地私有包到其它项目 就是自己写的包想在其他项目用可以按照如下步骤进行导入。 5.4.1 创建模拟用的本地私有包 比如说我在这个目录下创建了新的代码文件 然后写了新的代码 package calcimport fmtfunc Multply(x, y int) int {fmt.Println(这是新的私有的calc包)return x * y } 5.4.2 在mian.go中使用新的这个calc包 先在main.go中定义导入的包可以随便写一个包名 package mainimport (tools/abcd // 随便写 ) 修改go.mod 但此时注意module test这里报错了 意思是在新的这个包路径中找不到go.mod所以需要初始化一下。 PS D:\个人\学习\Go\私有包\calc go mod init calc go: creating new go.mod: module calc go: to add module requirements and sums:go mod tidy 在main.go中使用这个新的私有包 package mainimport (c tools/abcd // c相当于是包的别名 )func main() {c.Multply(2, 3) } 调试结果 这是新的私有的calc包 5.5 导入第三方包 这个不做演示了官放文档都有直接go get -u下载就行了。前面的文章也有演示百度也大把。 6. init函数 6.1 init函数的作用 init函数主要是配合匿名导入使用目的不是为了让你使用包内的资源而是运行该包所有的init。 所有的包中都可以定义init函数。 注意 init函数在本包内可以有n多个但是每个.go文件中只能有1个。同一个包内的多个init函数执行顺序是没有办法保证的。不同包的init函数的执行顺序由导入顺序决定init函数无参无返回值不能被其他函数调用。包中的init函数将在main函数之前自动执行。 6.2 代码演示 6.2.1 在子包中创建init函数 6.2.1.1 minus.go 6.2.1.2 calc.go 6.2.2 在main.go中调用 package mainimport (fmt_ test/calc_ test/calc/minus )func main() {fmt.Println(这是main.go中的init函数测试) } 调试结果 这是calc/calc.go中的init函数 这是calc/minus/minus.go中的init函数 这是main.go中的init函数测试 7.  反射 反射有很大的弊端这里略过了。 反射的弊端 代码难以阅读难以维护。编译期间不能发现类型错误覆盖测试难度很大有些Bug需要线上运行时才可能发现并造成严 重后果。反射性能很差通常比正常代码慢一到两个数量级。如果性能要求高时或反复调用的代码块里建 议不要使用反射。 反射主要应用场合就是写库或框架一般用不到再一个面试时候极低概率被问到。
http://www.zqtcl.cn/news/245819/

相关文章:

  • 做设计灵感的网站网站网站建设
  • 华强北附近网站建设电商网站建设规划
  • 泰和网站制作长尾词排名优化软件
  • 国外做的好的鲜花网站万网二手已备案域名
  • 那个网站做的系统最好开奖视频网站开发
  • 学设计的网站推荐南京做网站南京乐识专业
  • 企业网站建设调查问卷重庆网站制作外包
  • 要建设一个网站需要什么北京优化网站公司
  • 多语言网站建设方案大同建设网站
  • 测网站打开的速度的网址wordpress 逻辑代码
  • 网站代码开发徐州网站建设青州陈酿
  • 建网站的软件有哪些做网站怎么挣钱赚钱
  • 徐州市建设局招投标网站谷歌网站的主要内容
  • 门户网站建设工作情况汇报花店网站建设课程设计论文
  • 长春绿园网站建设哪里制作企业网站
  • 建设网站计划ppt模板核酸二维码
  • 宁波网络推广制作seo关键词推广公司
  • 东莞市网站推广西安推广公司无网不胜
  • 全国网站建设有实力建筑人才网123
  • 海安网站设计公司网站开发好学嘛
  • 网站建设深圳公司上海贸易公司注册条件
  • 深圳市坪山新区建设局网站给别人做网站去掉版权
  • 怎么做监测网站的浏览量有没有专业做股指的评论网站
  • 济南微信网站开发网上效果代码网站可以下载吗
  • 门户网站的设计常见的管理信息系统有哪些
  • 网站添加悬浮二维码成都游戏网站开发
  • 用jquery做网站百度seo排名规则
  • 免备案手机网站室内设计说明
  • 网站被做站公司贩卖怎样将qq空间建设为个人网站
  • 网站开发有哪几类淮安app开发公司