内容简介:在开发中,我们经常会使用到环境变量,Go语言默认也提供了提取环境变量的内置方法,比如使用本文将从库介绍、原理分析、源码解析、不足四方面展开。Github:
在开发中,我们经常会使用到环境变量,Go语言默认也提供了提取环境变量的内置方法,比如使用 syscall.Getenv(key)
方法,或者是对其的封装 os.LookupEnv(key)
这个方法,都能使我们便捷的获取到环境变量。但是通过内置方法获取到的环境变量返回的是字符串类型的,往往还需要我们对其进行类型转换,为了避免重复工作,今天给大家介绍一款支持将环境变量解析到结构体,并进行类型转换的库。
本文将从库介绍、原理分析、源码解析、不足四方面展开。
2. env库介绍
2.1 安装
Github: https://github.com/caarlos0/env
使用Go mod: github.com/caarlos0/env/v6
2.2 快速入门
package main import ( "os" "fmt" "github.com/caarlos0/env/v6" ) type MyEnv struct { Path string `env:"PATH"` } func main() { myenv := MyEnv{} if err := env.Parse(&myenv); err != nil { fmt.Printf("%+v\n", err) os.Exit(-1) } fmt.Printf("%+v\n", myenv) } 复制代码
执行以上代码可以看到如下输出:
{Path:/usr/local/opt/openssl@1.1/bin:/Users/user/.nvm/versions/node/v10.15.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Users/user/Library/Python/2.7/bin:/usr/local/go/bin} 复制代码
成功的获取到了我们的环境变量中的PATH,并赋值给了 myenv
这个 MyEnv
结构体实例的 Path
字段。
2.3 标签
这个库是通过反射来解析Tag实现值绑定的,所以需要了解怎么配置结构体的标签。
2.3.1 env
默认必须配置的标签,没有配置则该字段不会被解析。比如在前面我们给 MyEnv
这个结构体的 Path
字段配置了 env
标签,并且值是 PATH
,它代表库将会把环境变量中的 PATH
的值赋给 Path
字段,并且是一个字符串类型。
2.3.1.1 选项
env
标签同时支持一些选项的功能。
2.3.1.1.1 required
required
选项表示这个环境变量必须存在,不存在则会报错,没有此选项的话,在不存在这个环境变量的情况下会采用默认值或空值来作为值。
type MyEnv struct { GoVersion string `env:"GOVERSION,required"` } 复制代码
如上,如果环境变量中不存在 GOVERSION
,则会返回错误。
2.3.1.1.2 file
此选项表示将根据环境变量的值去取某个文件,并将这个文件的数据赋值到当前变量,如下:
type MyEnv struct { Log string `env:"LOG_FILE,file"` } 复制代码
以上代码将尝试读取环境变量 LOG_FILE
,如此变量值为 ./out.log
,则尝试读取 ./out.log
文件的内容,最终返回给 Log
字段。
2.3.2 envDefault
支持通过此标签设置默认值,以下代码会尝试获取 GOROOT
环境变量,如未设置则默认给 GoRoot
字段赋值为 /usser/local/go
type MyEnv struct { GoRoot string `env:"GOROOT" envDefault:"/user/local/go"` } 复制代码
2.3.3 envExpand
此标签标示是否展开值,即如果值中存在变量,则会使用变量的值替换变量,展开会最终的值。如下代码所示,假如要获取的 GOPATH
这环境变量的值为 $HOME/go
, HOME
这个环境变量的值为 /User/user
,则 GoPath
这个字段的最终值为 /User/user/go
。
type MyEnv struct { GoPath string `env:"GOPATH" envExpand:"true"` } 复制代码
2.3.4 envSeparator
此标签定义字符串的分隔符,常用于切片类型,默认的分隔符是 ,
,如下代码:
type MyEnv struct { Ports []int `env:"PORTS" envSeparator:":"` Users []string `env:"USERS"` } 复制代码
这时环境变量为:
PORTS=123:456:789 USERS=one,two 复制代码
这样我们可以得到 Ports
字段为 [123, 456, 789]
, Users
字段为 ['one', 'two']
2.4 解析方法
2.4.1 默认支持
env库默认支持了一些类型的解析,这些解析又分为内建的和普通的类型转换。
内建的如下:
bool int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float32 float64 string 复制代码
普通的类型转换如下:
time.Duration url.URL 复制代码
还有一种是通过判定是否支持 encoding.TextUnmarshaler
接口来决定是否进行 UnmarshalText
。
2.4.2 自定义解析
env库中定义了一个 ParserFunc
方法,只要实现这个方法并调用 ParseWithFuncs
传入自定义方法,即可实现自定义的类型解析。 ParserFunc
方法定义如下:
type ParserFunc func(v string) (interface{}, error) 复制代码
自定义解析方法示例如下:
package main import ( "fmt" "github.com/caarlos0/env/v6" "os" "reflect" ) type ATest struct { PWD string `env:"PWD"` PATH A `env:"PATH"` } type A struct { Value string } func ParseA(v string) (interface{}, error) { return A{v + ":/some/other/path"}, nil } func main() { atest := ATest{} pm := map[reflect.Type]env.ParserFunc{ reflect.TypeOf(A{}): ParseA, } if err := env.ParseWithFuncs(&atest, pm); err != nil { fmt.Printf("Err:%+v\n", err) os.Exit(-1) } fmt.Printf("%+v\n", atest.PATH.Value) } 复制代码
以上代码运行最终会输出:
/usr/local/opt/openssl@1.1/bin:/Users/user/.nvm/versions/node/v10.15.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Users/user/Library/Python/2.7/bin:/usr/local/go/bin:/some/other/path 复制代码
可以看到 PATH
环境变量的值被添加上了 /some/other/path
最终给到了 Path
字段下的 Value
字段。
3 原理解析
如下图,env库给外部主要暴露了 Parse
和 ParseWithFuncs
两个方法, Parse
方法其实只是封装了一层 ParseWithFuncs
方法,给了他一个空的自定义解析方法Map。 ParseWithFuncs
会将传入的自定义解析方法和库中定义的解析方法合并,然后调用 doParse
方法来做解析, doParse
方法遍历结构体下的所有字段,如果为指针型会继续调用 ParseWithFuncs
解析,如果为结构体,则会继续调用 Parse
方法解析。在具体的解析阶段,会先调用 get
方法获取环境变量的值, get
方法会根据前面设定的标签的属性和选项等取得相应的值,然后通过 set
方法将赋值到对应的字段上,在 set
方法中还会判断是否是切片类型,或者是否实现了 TextUnmarshaler
接口,来做对应的处理。
整体上,env库是充分利用了go的反射原理进行相应的标签解析和值类型转换的。
本篇先介绍前两部分,如果喜欢请点赞和关注,下一篇继续源码分析部分。
欢迎关注我们的微信公众号,每天学习Go知识
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
百度SEO一本通
潘坚、李迅 / 电子工业出版社 / 2015-6 / 59.00元
《百度SEO一本通》通过浅显易懂的叙述方式,以及大量的图示,详细介绍了SEO的关键技术要点,对于搜索引擎优化中重要的关键词优化、链接优化,以及百度推广中的推广技巧都进行了详细的介绍。 《百度SEO一本通》共分为11章,首先让大家了解SEO存在的原因,然后对网页、网站、空间和程序与SEO的关系展开了细节上的讨论,最后几章深入介绍了百度推广的相关概念、设置、技巧和实操,让读者可以轻松上手操作,易......一起来看看 《百度SEO一本通》 这本书的介绍吧!