请教一个包导入问题,百思不得解

2019-06-19 08:37:17 +08:00
 wewin

项目结构如下:

decoder
      ├── config.json
      └── decoder.go

config.json 文件内容

{
    "ServerInfo": {
        "Host": "127.0.0.1:8888"
    },
    "RedisInfo": {
        "Host": "127.0.0.1:6379",
        "MaxIdle":     16,
        "MaxActive":   0,
        "IdleTimeout": 300
    }
}

decoder.go 文件内容

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "time"
)

type Config struct{}

type ConfigurationType struct {
    ServerInfo ServerInfoType
    RedisInfo  RedisInfoType
}

type ServerInfoType struct {
    Host string
}

type RedisInfoType struct {
    Host        string
    MaxIdle     int
    MaxActive   int
    IdleTimeout time.Duration
}

var Configuration = ConfigurationType{}

func (this Config) InitConfig() {
    file, _ := os.Open("config.json")
    defer file.Close()
    decoder := json.NewDecoder(file)
    Configuration = ConfigurationType{}
    err := decoder.Decode(&Configuration)
    if err != nil {
        fmt.Println("Error: ", err)
    }
    fmt.Printf("Configuration: %v\n", Configuration)
}

func main() {
    conf := Config{}
    conf.InitConfig()
}

这种情况下我运行:go run decoder.go , 输出结果如下:

Configuration: {{127.0.0.1:8888} {127.0.0.1:6379 16 0 300ns}}

但是我把这个 main 包改为 decoder 包,项目结构调整如下

.
├── decoder
│   ├── config.json
│   └── decoder.go
└── main.go

config.json 文件内容


{
    "ServerInfo": {
        "Host": "127.0.0.1:8888"
    },
    "RedisInfo": {
        "Host": "127.0.0.1:6379",
        "MaxIdle":     16,
        "MaxActive":   0,
        "IdleTimeout": 300
    }
}

decoder.go 文件内容

package decoder

import (
    "encoding/json"
    "fmt"
    "os"
    "time"
)

type Config struct{}

type ConfigurationType struct {
    ServerInfo ServerInfoType
    RedisInfo  RedisInfoType
}

type ServerInfoType struct {
    Host string
}

type RedisInfoType struct {
    Host        string
    MaxIdle     int
    MaxActive   int
    IdleTimeout time.Duration
}

var Configuration = ConfigurationType{}

func (this Config) InitConfig() {
    file, _ := os.Open("config.json")
    defer file.Close()
    decoder := json.NewDecoder(file)
    Configuration = ConfigurationType{}
    err := decoder.Decode(&Configuration)
    if err != nil {
        fmt.Println("Error: ", err)
    }
    fmt.Printf("Configuration: %v\n", Configuration)
}

main.go 文件内容

package main

import "initTest/decoder"

func main() {
    t := decoder.Config{}
    t.InitConfig()
}

测试运行 go run main.go 报错如下:

Error:  invalid argument
Configuration: {{} { 0 0 0s}}

请问是否有人知道是什么原因?

3009 次点击
所在节点    Go 编程语言
11 条回复
freestyle
2019-06-19 08:44:33 +08:00
这不是包导入的问题, file, _ := os.Open("config.json") 你用的是相对路径,会从运行的工作目录(执行 go run main.go 的目录)下查找,实际上代码运行到这一步就出错了,找不到文件. 配置文件路径应该用函数参数去传递,而不是写死在函数里面. 要正确处理 error.
wewin
2019-06-19 08:52:46 +08:00
@freestyle 哎哟,我去,被闪了腰。现在用的语言文件找不到直接是跑出了异常,go 语言这种直接返回 err 的还真的不太习惯。

将 decoder.go InitConfig 方法改了:
```
...
func (this Config) InitConfig() {
file, err := os.Open("config.json")
defer file.Close()
if err != nil {
fmt.Printf("Open file error: %v\n", err)
}

decoder := json.NewDecoder(file)
Configuration = ConfigurationType{}
err = decoder.Decode(&Configuration)
if err != nil {
fmt.Println("Error: ", err)
}
fmt.Printf("Configuration: %v\n", Configuration)
}
```
将读文件的 err 信息打印出来了。

感谢!
donething
2019-06-19 13:10:14 +08:00
再挑个次要问题,defer file.Close()应该放在 if err != nil 之后
wewin
2019-06-19 14:08:47 +08:00
@donething 这是为什么呢?`defer` 语句不是在方法返回前触发的吗?
donething
2019-06-19 15:10:57 +08:00
@wewin 如果打开文件若有错误发生,就不需要调用 file.Close(),所以写在 if err!=nil 语句后面。
wewin
2019-06-19 18:57:23 +08:00
@donething 你的意思是这样?
```
if err != nil {

}
```
wewin
2019-06-19 18:59:09 +08:00
@donething 你的意思是这样?
```
if err != nil {
defer file.close()
}
```
donething
2019-06-19 19:07:23 +08:00
if err != nil {
return err
}
defer file.close()
labulaka
2019-06-20 11:07:26 +08:00
任何时候别忽略 err
anonymous256
2019-06-20 23:20:21 +08:00
我也很烦 golang 每次都要判断 err,所以一般就写个函数
func checkErr(err error){
if err != nil{
// do something
}
}
这样每次都只直接调用这个 checkErr,而不是判断它是不是等于 nil 了,比较偷懒的写法
wewin
2019-06-24 08:51:40 +08:00
@donething 不错,经过测试发现自己对 defer 返回前调用理解有误。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/575332

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX