{"id":43027522,"url":"https://github.com/tietang/props","last_synced_at":"2026-01-31T07:10:34.343Z","repository":{"id":56122725,"uuid":"93932091","full_name":"tietang/props","owner":"tietang","description":"config source library for golang, support properties/yaml/ini file、zookeeper\\consul\\etcd k/v  k/props ","archived":false,"fork":false,"pushed_at":"2026-01-14T13:13:21.000Z","size":11062,"stargazers_count":64,"open_issues_count":2,"forks_count":20,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-14T16:54:34.086Z","etag":null,"topics":["config","consul","consul-key","go-properties","go-props","go-zookeeper","golang","properties","zookeeper"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tietang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-10T10:26:28.000Z","updated_at":"2026-01-14T13:12:48.000Z","dependencies_parsed_at":"2023-02-19T03:31:09.590Z","dependency_job_id":null,"html_url":"https://github.com/tietang/props","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/tietang/props","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tietang%2Fprops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tietang%2Fprops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tietang%2Fprops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tietang%2Fprops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tietang","download_url":"https://codeload.github.com/tietang/props/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tietang%2Fprops/sbom","scorecard":{"id":884993,"data":{"date":"2025-08-11","repo":{"name":"github.com/tietang/props","commit":"ed299a1b1ba390b99553366c3fe1f05c0d05fbfd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.2,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Info: Possibly incomplete results: error parsing shell code: invalid UTF-8 encoding: zk/zookeeper/mock.jar:0","Warn: containerImage not pinned by hash: .circleci/images001/primary/Dockerfile:1: pin your Docker image by updating golang:1.10.3 to golang:1.10.3@sha256:3c54fa85d6262d2ef7695ee2f8793f1f4f9809ce4a08ca2e213235ef4cfdcb66","Warn: containerImage not pinned by hash: .circleci/images001/primary/Dockerfile:2","Warn: goCommand not pinned by hash: deps.sh:3","Warn: goCommand not pinned by hash: deps.sh:4","Warn: goCommand not pinned by hash: deps.sh:5","Warn: goCommand not pinned by hash: deps.sh:6","Warn: goCommand not pinned by hash: deps.sh:7","Warn: goCommand not pinned by hash: deps.sh:8","Warn: goCommand not pinned by hash: deps.sh:9","Warn: goCommand not pinned by hash: deps.sh:10","Warn: goCommand not pinned by hash: deps.sh:11","Warn: goCommand not pinned by hash: deps.sh:12","Warn: goCommand not pinned by hash: deps.sh:13","Warn: goCommand not pinned by hash: deps.sh:14","Warn: goCommand not pinned by hash: deps.sh:15","Warn: goCommand not pinned by hash: deps.sh:16","Warn: goCommand not pinned by hash: deps.sh:17","Warn: goCommand not pinned by hash: deps.sh:18","Warn: goCommand not pinned by hash: deps.sh:19","Warn: goCommand not pinned by hash: deps.sh:20","Warn: goCommand not pinned by hash: deps.sh:21","Warn: goCommand not pinned by hash: deps.sh:22","Info:   2 out of  22 goCommand dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":6,"reason":"4 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2020-0017 / GHSA-w73w-5m7g-f7qc","Warn: Project is vulnerable to: GO-2021-0053 / GHSA-c3h9-896r-86jm","Warn: Project is vulnerable to: GO-2020-0019 / GHSA-3xh2-74w9-5vxm","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T09:40:20.923Z","repository_id":56122725,"created_at":"2025-08-24T09:40:20.923Z","updated_at":"2025-08-24T09:40:20.923Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28932644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T04:05:25.756Z","status":"ssl_error","status_checked_at":"2026-01-31T04:02:35.005Z","response_time":128,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["config","consul","consul-key","go-properties","go-props","go-zookeeper","golang","properties","zookeeper"],"created_at":"2026-01-31T07:10:33.529Z","updated_at":"2026-01-31T07:10:34.325Z","avatar_url":"https://github.com/tietang.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# props\n\n[![Build Status](https://travis-ci.org/tietang/props.svg?branch=master)](\u003chttps://travis-ci.org/tietang/props\u003e)\n[![GoDoc Documentation](http://godoc.org/github.com/tietang/props?status.png)](\u003chttps://godoc.org/github.com/tietang/props\u003e)\n[![Sourcegraph](https://sourcegraph.com/github.com/tietang/props/-/badge.svg)](https://sourcegraph.com/github.com/tietang/props?badge)\n[![Coverage Status](https://coveralls.io/repos/github/tietang/props/badge.svg?branch=master)](https://coveralls.io/github/tietang/props?branch=master)\n[![GitHub release](https://img.shields.io/github/release/tietang/props.svg)](https://github.com/tietang/props/releases)\n\n统一的配置工具库，将各种配置源抽象或转换为类似properties格式的key/value，并提供统一的API来访问这些key/value。支持\nproperties 文件、ini 文件、zookeeper k/v、zookeeper k/props、consul k/v、consul k/props等配置源，并且支持通过\nUnmarshal从配置中抽出struct；支持上下文环境变量的eval，${}形式；支持多种配置源组合使用。\n\n## 特性\n\n### 支持的配置源：\n\n- properties格式文件\n- ini格式文件\n- yaml格式文件\n- [Apollo](\u003chttps://github.com/ctripcorp/apollo\u003e) k/v,k/props,k/ini,k/yaml\n    - 支持热更新\n    - 支持命名空间的更新监听\n- [Nacos](\u003chttp://nacos.io\u003e) k/props[properties],k/yaml,k/ini,k/ini_props\n    - 支持热更新\n- zookeeper k/v\n    - 支持节点更新监听\n- zookeeper k/props[properties],k/yaml,k/ini,k/ini_props\n    - 支持节点更新监听\n- consul k/v\n- consul k/props[properties],k/yaml,k/ini,k/ini_props\n- etcd API V2 k/v\n- etcd API V2 k/props\n- etcd API V3 k/v\n- etcd API V3 k/props\n\n### key/value支持的数据类型：\n\n- key只支持string\n- value 5种数据类型的支持：\n    - string\n    - int\n    - float64\n    - bool\n    - time.Time\n        - 常见的时间格式\n        - 毫秒数\n    - time.Duration：\n        - 比如 \"300ms\", \"-1.5h\" or \"2h45m\".\n        - 合法的时间单位： \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n\n### 其他特性\n\n- Unmarshal支持\n- 多种key隐射支持\n    - 比如：`ServerPort` 可以映射为 `server_port` 、`ServerPort`、 `serverPort` 、 `server-port`、等\n    - 存在多个key时，按照如下顺序，越靠后优先级越高： server_port_val server-port-val serverPortVal server_port_val【config tag】\n- 支持tag\n  - 自定义key tag：props ，比如：MQTTVal, props:\"mqtt_val\"\n  - 支持多种key tag：yaml,yam,ini,json\n  - 默认值tag: val\n  - 结构体tag: prefix\n- 上下文变量eval支持，`${}`形式\n- 支持多配置源组合\n- 默认添加了系统环境变量，优先级最低\n\n## Install\n\n\u003e go get -u github.com/tietang/props/v3\n\n**或者通过go mod：**\n\n\n\u003e go mod tidy\n\n## 配置源和配置形式使用方法：\n\n### properties格式文件\n\n格式：`[key][=|:][value] \\n`\n每行为key/value键值对 ,用`=`或`：`分割，key可以是除了`=`和`:`、以及空白字符的任何字符\n\n例子：\n\n`server.port=8080`\n\n或者\n\n`server.port: 8080`\n\n### 通过kvs.ReadPropertyFile读取文件\n\n```golang\n\np, err := kvs.ReadPropertyFile(\"config.properties\")\nif err != nil {\npanic(err)\n}\nstringValue, err := p.Get(\"prefix.key1\")\nfmt.Println(stringValue, err)\n//如果不存在，则返回默认值\nstringDefaultValue := p.GetDefault(\"prefix.key1\", \"default value\")\nfmt.Println(stringDefaultValue)\nboolValue, err := p.GetBool(\"prefix.key2\")\nfmt.Println(boolValue)\nboolDefaultValue := p.GetBoolDefault(\"prefix.key2\", false)\nfmt.Println(boolDefaultValue)\nintValue, err := p.GetInt(\"prefix.key3\")\nfmt.Println(intValue)\nintDefaultValue := p.GetIntDefault(\"prefix.key3\", 1)\nfmt.Println(intDefaultValue)\nfloatValue, err := p.GetFloat64(\"prefix.key4\")\nfmt.Println(floatValue)\nfloatDefaultValue := p.GetFloat64Default(\"prefix.key4\", 1.2)\nfmt.Println(floatDefaultValue)\n\n```\n\n#### 通过kvs.NewProperties()从io.Reader中读取\n\n```\n p := kvs.NewProperties()\n p.Load(strings.NewReader(\"some data\"))\n p.Load(bytes.NewReader([]byte(\"some data\")))\n```\n\n#### 通过kvs.NewPropertiesConfigSource()\n\n```\nfile := \"/path/to/config.properties\"\np := kvs.NewPropertiesConfigSource(file)\np = kvs.NewPropertiesConfigSourceByFile(\"name\", file)\n//通过map构造内存型\nm := make(map[string]string)\nm[\"key\"]=\"value\"\np = kvs.NewPropertiesConfigSourceByMap(\"name\", m)\n\n```\n\n#### Properties ConfigSource\n\n```golang\n\nvar cs kvs.ConfigSource\n//\ncs = kvs.NewPropertiesConfigSource(\"config.properties\")\ncs = kvs.NewPropertiesConfigSourceByFile(\"config\", \"config.properties\")\n\n\nstringValue, err := cs.Get(\"prefix.key1\")\n//如果不存在，则返回默认值\nstringDefaultValue := cs.GetDefault(\"prefix.key1\", \"default value\")\nboolValue, err := cs.GetBool(\"prefix.key2\")\nboolDefaultValue := cs.GetBoolDefault(\"prefix.key2\", false)\nintValue, err := cs.GetInt(\"prefix.key3\")\nintDefaultValue := cs.GetIntDefault(\"prefix.key3\", 1)\nfloatValue, err := cs.GetFloat64(\"prefix.key4\")\nfloatDefaultValue := cs.GetFloat64Default(\"prefix.key4\", 1.2)\n\n```\n\n### ini格式文件。\n\n格式：参考 [wiki百科：INI_file](\u003chttps://en.wikipedia.org/wiki/INI_file\u003e)\n​\n\n```ini\n[section]\n[key1][=|:][value1]\n[key1][=|:][value1]\n...\n```\n\n不支持sub section\n\n例子：\n\n```ini\n[server]\nport : 8080\nread.timeout = 6000ms\n\n[client]\nconnection.timeout = 6s\nquery.timeout = 6s\n```\n\n#### 使用方法：\n\n```golang\nfile := \"/path/to/config.ini\"\np := ini.NewIniFileConfigSource(file)\np = ini.NewIniFileConfigSourceByFile(\"name\", file)\n```\n\n### Nacos\n\n只支持key/properties配置形式。\n\n例如有如下配置：\n\nhttp://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test.id\u0026group=testGroup\u0026tenant=testTenant\n\n```properties\nkey-0.x0=value-00\nkey-0.x1=value-01\nkey-0.x2=value-02\n```\n\n基本用法：\n\n```go\n address := \"127.0.0.1:8848\"\nc := NewNacosPropsConfigSource(address)\nc.DataId = \"test.id\"\nc.Tenant = \"testTenant\"\nc.Group = \"testGroup\"\nv :=c.GetDefault(\"key-0.x0\", \"defaultval\") //value-00\n\n```\n\n### zookeeper\n\n支持key/value和key/properties配置形式，key/properties配置和ini类似，将key作为section name。\n\nkey/value形式，将path去除root path部分并替换`/`为`.`作为key。\n\nkey/properties形式，在root path下读取所有子节点，将子节点名称作为section\nname，value为子properties格式内存，通过子节点名称和子properties中的key组合成新的key作为key。\n\n#### by zookeeper key/value\n\n##### 基本例子\n\n```golang\nroot := \"/config/kv/app1/dev\"\nvar conn *zk.Conn\np := zk.NewZookeeperConfigSource(\"zookeeper-kv\", root, conn)\n```\n\n##### CompositeConfigSource多context例子\n\n```golang\nvar cs kvs.ConfigSource\nurls := []string{\"172.16.1.248:2181\"}\ncontexts := []string{\"/configs/apps\", \"/configs/users\"}\ncs = zk.NewZookeeperCompositeConfigSource(contexts, urls, time.Second*3)\n\n```\n\n#### 用properties来配置： key/properties\n\nvalue值为properties格式内容, 整体设计类似ini格式,例如：\n\n##### key:\n\n/config/kv/app1/dev/datasource\n\n##### value:\n\n```properties\nurl=tcp(127.0.0.1:3306)/Test?charset=utf8\nusername=root\npassword=root\n\n```\n\n```golang\nroot := \"/config/kv/app1/dev\"\nvar conn *zk.Conn\np := zk.NewZookeeperIniConfigSource(\"zookeeper-props\", root, conn)\n\n```\n\n### consul 多层key/value形式\n\n#### by consul key/value\n\n```golang\n例如：\n\nconfig101/test/demo1/server/port= 8080\n\n获取的属性和值是：\n\nserver.port = 8080\n\naddress := \"127.0.0.1:8500\"\nroot := \"config101/test/demo1\"\nc := consul.NewConsulKeyValueConfigSource(\"consul\", address, root)\nstringValue, err := cs.Get(\"prefix.key1\")\nstringDefaultValue := cs.GetDefault(\"prefix.key1\", \"default value\")\n\n```\n\n#### 用properties来配置： key/properties\n\nvalue值为properties格式内容, 整体设计类似ini格式,配置样式如下图：\n\n![](\u003cdocs/consul_key_kvs.png\u003e)\n\n```golang\nroot := \"config/app1/dev\"\naddress := \"127.0.0.1:8500\"\np := consul.NewConsulIniConfigSourceByName(\"consul-props\", address, root)\n```\n\n### 支持Unmarshal\n\n支持的数据类型：\n\n- int,int8,int16,int32,int64\n- uint,uint8,uint16,uint32,uint64\n- string\n- bool\n- float32,float64\n- map\n- time.Duration\n- struct: 包括嵌套、内嵌、匿名、组合、嵌套/内嵌+匿名\n- map：key只支持string，value支持struct\n\n##### Unmarshal struct\n\n在struct中规定命名为`_prefix `、类型为`string `、并且指定了`prefix`tag, 使用feild `_prefix `的`prefix`tag作为前缀，将struct\nfeild名称转换后组合成完整的key，并从ConfigSource中获取数据并注入struct实例，feild类型只支持ConfigSource所支持的数据类型（string、int、float、bool、time.Duration）。\n\n##### Unmarshal flat struct\n\n```golang\n\n\ntype Port struct {\nPort    int  `val:\"8080\"`\nEnabled bool `val:\"true\"`\n}\ntype ServerProperties struct {\n_prefix string        `prefix:\"http.server\"`\nPort    Port\nTimeout int           `val:\"1\"`\nEnabled bool\nFoo     int           `val:\"1\"`\nTime    time.Duration `val:\"1s\"`\nFloat   float32       `val:\"0.000001\"`\nParams  map[string]string\nTimes      map[string]time.Duration\n}\n\nfunc main() {\n\np := kvs.NewMapProperties()\np.Set(\"http.server.port.port\", \"8080\")\np.Set(\"http.server.params.k1\", \"v1\")\np.Set(\"http.server.params.k2\", \"v2\")\np.Set(\"http.server.Times.m1\", \"1s\")\np.Set(\"http.server.Times.m2\", \"1h\")\np.Set(\"http.server.Times.m3\", \"1us\")\np.Set(\"http.server.port.enabled\", \"false\")\np.Set(\"http.server.timeout\", \"1234\")\np.Set(\"http.server.enabled\", \"true\")\np.Set(\"http.server.time\", \"10s\")\np.Set(\"http.server.float\", \"23.45\")\np.Set(\"http.server.foo\", \"23\")\ns := \u0026ServerProperties{\nFoo:   1234,\nFloat: 1234.5,\n}\np.Unmarshal(s)\nfmt.Println(s)\n\n}\n\n\n```\n\nUnmarshal flat struct\n\n根据前缀和key，以struct结构层级进行反序列化，key的层级和结构体一一对应，每一层级的key和结构体field名称一致，切第一个字母位小写或者全部小写并用-分割的风格。\n\n### Unmarshal 内嵌 struct\n\n内嵌结构体会**忽略**内嵌结构体名称作为key。比如如下结构体：\n\n```golang\ntype PlatStruct struct {\nStrVal      string\nIntVal      int\nDurationVal time.Duration\nBoolVal     bool\n}\ntype OuterStruct struct {\nPlatStruct\n}\n```\n\n前缀未：ums\n\n那么这个结构体对应的key/value应该是：\n\n```\nums.strVal=str\nums.intVal=123\nums.durationVal=1s\nums.boolVal=true\n```\n\n##### Unmarshal 嵌套 struct\n\n嵌套结构体会将嵌套的结构体名称作为key。比如如下结构体：\n\n```golang\ntype OuterStruct struct {\nInner struct {\nStrVal      string\nIntVal      int\nDurationVal time.Duration\nBoolVal     bool\n}\n}\n```\n\n那么这个结构体对应的key/value应该是：\n\n```\nums.inner.strVal=str\nums.inner.intVal=123\nums.inner.durationVal=1s\nums.inner.boolVal=true\n```\n\n##### Unmarshal Map\n\n```golang\n\ntype PlatStruct struct {\nStrVal      string\nIntVal      int\nDurationVal time.Duration\nBoolVal     bool\n}\nps := NewMapProperties()\nps.Set(\"ums.test1.strVal\", STR_VAL)\nps.Set(\"ums.test1.intVal\", INT_VAL_STR)\nps.Set(\"ums.test1.durationVal\", DURATION_VAL_STR)\nps.Set(\"ums.test1.boolVal\", BOOL_VAL_STR)\n\nps.Set(\"ums.test2.strVal\", STR_VAL)\nps.Set(\"ums.test2.intVal\", INT_VAL_STR)\nps.Set(\"ums.test2.durationVal\", DURATION_VAL_STR)\nps.Set(\"ums.test2.boolVal\", BOOL_VAL_STR)\n\nm := make(map[string]*PlatStruct, 0)\nerr := Unmarshal(ps, m, \"ums\")\n\n```\n\n如上代码，以ums作为前缀，test1和test2作为map key，ums.test1和ums.test2后面的key将根据struct进行反序列化，key的层级和结构体一一对应。\n\n### 上下文变量表达式（或者占位符）的支持\n\n支持在props上下文中替换占位符：`${}`\n\n```\np := kvs.NewEmptyMapConfigSource(\"map2\")\np.Set(\"orign.key1\", \"v1\")\np.Set(\"orign.key2\", \"v2\")\np.Set(\"orign.key3\", \"2\")\np.Set(\"ph.key1\", \"${orign.key1}\")\np.Set(\"ph.key2\", \"${orign.key1}:${orign.key2}\")\np.Set(\"ph.key3\", \"${orign.key3}\")\nconf := kvs.NewDefaultCompositeConfigSource(p)\nphv1, err := conf.GetInt(\"ph.key1\")//v1\nphv2, err := conf.Get(\"ph.key2\")//v1:v1\nphv3, err := conf.GetInt(\"ph.key3\")//2\n\n```\n\n### 多种配置源组合使用\n\n优先级以追加相反的顺序,最后添加优先级最高。\n\n```golang\n\nkv1 := []string{\"go.app.key1\", \"value1\", \"value1-d\"}\nkv2 := []string{\"go.app.key2\", \"value2\", \"value2-d\"}\n\np1 := kvs.NewEmptyMapConfigSource(\"map1\")\np1.Set(kv1[0], kv1[1])\np1.Set(kv2[0], kv2[1])\np2 := kvs.NewEmptyMapConfigSource(\"map2\")\np2.Set(kv1[0], kv1[2])\np2.Set(kv2[0], kv2[2])\nconf.Add(p1)\nconf.Add(p2)\n\n//value1==value1-d\nvalue1, err := conf.Get(kv1[0])\nfmt.Println(value1)\n//value2=value2-d\nvalue2, err := conf.Get(kv2[0])\nfmt.Println(value2)\n\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftietang%2Fprops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftietang%2Fprops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftietang%2Fprops/lists"}