英文:
Golang sharing configurations between packages
问题
所以我刚开始学习Go编程语言,花了很多时间查看示例、参考资料等等。正如大多数人会同意的,学习一门语言最好的方法就是深入其中并开始做一些东西,这也是我目前正在尝试做的。我正在构建一个Restful Web服务。我已经成功运行了基本功能,比如插入数据库、注册路由等等。然而,在过去的两天里,我一直在努力实现应用程序的配置/属性。可能是因为我是新手,我的Go项目架构完全错误,所以我才遇到这样的困难。下面是我的项目结构:
src
server
database
dbaccess.go
dbcomm.go
handling
handler.go
handlercomm.go
models
config.go
response.go
user.go
routing
routes.go
main.go
这是我的config.go文件:
package models
import (
"io/ioutil"
"encoding/json"
)
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
}
这是我的main函数:
func main(){
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
config := models.NewConfig(args[0])
port := config.Server["PORT"]
router := routing.NewRouter()
fmt.Printf( "-------------------------------------------------\n"+
"Listening and Serving on Port %s\n"+
"-------------------------------------------------",port)
log.Fatal(http.ListenAndServe(":"+port,router))
}
最后,这是我的路由映射:
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
var routes = []Route{
Route{
"signup",
"POST",
"/signup",
handling.PostSignUpUser,
},
Route{
"authenticate",
"POST",
"/login",
handling.PostLogin,
},
}
func NewRouter() *mux.Router{
router := mux.NewRouter().StrictSlash(true)
for _,route := range routes{
router.Methods(route.Method)
.Path(route.Pattern)
.Name(route.Name)
.Handler(route.HandlerFunc)
}
return router
}
所以,正如你在main函数中看到的,我从文件中初始化了相关的配置,这是没问题的。但问题是,我该如何在数据库包中使用同一个config对象呢?因为我需要设置主机、端口等等。我可以再次解析文件,但我更希望从一开始就共享那个对象。请指点我正确的方向。
英文:
So I just started learning the Go programming language and have spent hours on end looking at examples, references and so forth. As most of you would agree there is no better way to learn a language than to dive in and make something, which is what I am attempting to do at the moment. I am building a Restful web service. I have managed to get the basics running as well as inserting into db, registering routes etc. However for the past two days I have been struggling to implement application configurations/properties. It could just be that since I'm newbie my Go project architecture is all wrong hence why I am having such difficulty with this. Without further a due here is my project structure
src
server
database
dbaccess.go
dbcomm.go
handling
handler.go
handlercomm.go
models
config.go
response.go
user.go
routing
routes.go
main.go
Here is my config.go
package models
import (
"io/ioutil"
"encoding/json"
)
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
This is my main
func main(){
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
config := models.NewConfig(args[0])
port := config.Server["PORT"]
router := routing.NewRouter()
fmt.Printf( "-------------------------------------------------\n"+
"Listening and Serving on Port %s\n"+
"-------------------------------------------------",port)
log.Fatal(http.ListenAndServe(":"+port,router))
}
And finally this is where my routes get mapped
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
var routes = []Route{
Route{
"signup",
"POST",
"/signup",
handling.PostSignUpUser,
},
Route{
"authenticate",
"POST",
"/login",
handling.PostLogin,
},
}
func NewRouter() *mux.Router{
router := mux.NewRouter().StrictSlash(true)
for _,route := range routes{
router.Methods(route.Method)
.Path(route.Pattern)
.Name(route.Name)
.Handler(route.HandlerFunc)
}
return router
}
So as you can see in my Main I initialise the relevant configurations from a file which is fine. But the issue is how would I go about using that same config object from main in the database package,since I will need to set Host,Ports etc ? I could parse the file again but I would prefer if I could share that one object from the start. Please point me in the right direction
答案1
得分: 5
我建议在config.go
中声明一个全局变量,并使用init()
函数进行初始化。这样,当任何包导入它时,你就知道该变量将始终被初始化。以下是一些代码示例:
package models
import (
"io/ioutil"
"encoding/json"
)
var (
Configuration Config
)
init() {
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
Configuration = NewConfig(args[0]) // 在这里进行配置初始化
}
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
}
var()
会在init()
之前运行,但init()
会在导入该包的代码之前运行。因此,如果main.go
导入了models
包,那么models
中的init()
将在main.go
内部的任何代码之前运行,从而在使用之前初始化变量Configuration
。
英文:
What I would suggest is declaring a global variable in config.go
and initialize it using the init()
function. That way, you know that the variable will always be initialized when any package imports it. Here's some code:
package models
import (
"io/ioutil"
"encoding/json"
)
var (
Configuration Config
)
init() {
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
Configuration = NewConfig(args[0]) // configuration initialized here
}
type Config struct {
Db map[string]string `json:"db"`
Server map[string]string `json:"server"`
}
func NewConfig(fname string) *Config{
data,err := ioutil.ReadFile(fname)
if err != nil{
panic(err)
}
config := Config{}
err = json.Unmarshal(data,&config)
if err != nil {
panic(err)
}
return config
}
var()
is going to run before init()
, but init()
will run before the code in the package importing it. So if main.go
imports the models
package, then init()
in models
will run before any code inside main.go
and thus the variable Configuration
will be initialized before it is used.
答案2
得分: 2
现在你想要的只是提供一个可以在另一个包中使用的变量,解决方案很简单,记住,如果你声明一个以大写字母[A-Z]开头的变量名,这个变量就可以在Go的另一个包中可见并使用。
所以你只需要将main.go
中的config
重命名为Config
,并将其提取为全局变量:
var Config *models.Config
func main(){
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
Config = models.NewConfig(args[0])
port := Config.Server["PORT"]
router := routing.NewRouter()
fmt.Printf("-------------------------------------------------\n"+
"Listening and Serving on Port %s\n"+
"-------------------------------------------------", port)
log.Fatal(http.ListenAndServe(":"+port, router))
}
当你想在另一个包中使用它时,只需调用<包名>.Config
,包名是你的main.go
所属的包名,对于你的情况可能是main
。
英文:
Now what you want just is to provide a variable can be used in another package,the solution is easy,remember that if you declare a variable name begins with uppercase letter:[A-Z],this variable can be visible and used in another package in go.
So you just need to rename config
in your main.go
to Config
and extract it as global variable:
var Config *models.Config
func main(){
args := os.Args[1:]
if len(args) == 0{
fmt.Println("********************\nMust specify a config file in args\n********************")
os.Exit(1)
}
Config = models.NewConfig(args[0])
port := Config.Server["PORT"]
router := routing.NewRouter()
fmt.Printf( "-------------------------------------------------\n"+
"Listening and Serving on Port %s\n"+
"-------------------------------------------------",port)
log.Fatal(http.ListenAndServe(":"+port,router))
}
when you want to use it in another package,just call <package name>.Config
,the package name is the package name which your main.go belongs to,maybe main
in your case.
答案3
得分: 0
我已经为此构建了一个库,一个工具箱工厂(单例)和一个通用的配置解析器(支持yaml、json和toml),请查看一下,看看这个示例:SpareBox
英文:
I've built a library just for that, a toolbox factory (singletons) & an agnostic config parser (yaml, json and toml), give it a look, watch the example: SpareBox
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论