[英]How do I do this? Get an struct send to a func as interface and get it back as struct?
我是golang开发的新手,对与此问题相关的问题有一些疑问 。
作为一项学习练习,我试图创建一个简单的库来处理基于json的配置文件。 作为用于一个以上应用程序的配置文件,它应该能够处理不同的参数。 然后,我创建了一个具有文件名和数据接口的类型struct Configuration。 每个应用程序都将根据其配置需求具有结构。
在下面的代码中,我将所有内容放在一起(lib和“主代码”),“ TestData结构”是“应用程序参数”。 如果不存在,它将设置默认值并创建文件,并且文件正在运行。 但是当我尝试读取文件时。 我尝试解码json并将其放回数据接口。 但这给了我一个错误,我不知道该如何解决。 有人可以帮忙吗?
[更新]我之前没有输入目标代码,因为我虽然可以将它作为一个单独的程序轻松阅读。 为了更好地了解问题,贝娄是“目标代码”。 由于我将无法在库中使用TestData结构,因为它会因程序而异,所以处理此问题的唯一方法是使用接口。 有没有更好的办法?
库配置
package config
import (
"encoding/json"
"fmt"
"os"
)
// Base configuration struct
type Configuration struct {
Filename string
Data interface{}
}
func (c *Configuration) Create(cData *Configuration) bool {
cFile, err := os.Open(cData.Filename)
defer cFile.Close()
if err == nil {
fmt.Println("Error(1) trying to create a configuration file. File '", cData.Filename, "' may already exist...")
return false
}
cFile, err = os.Create(cData.Filename)
if err != nil {
fmt.Println("Error(2) trying to create a configuration file. File '", cData.Filename, "' may already exist...")
return false
}
buffer, _ := json.MarshalIndent(cData.Data, "", "")
cFile.Write(buffer)
return true
}
func (c *Configuration) Read(cData *Configuration) bool {
cFile, err := os.Open(cData.Filename)
defer cFile.Close()
if err != nil {
fmt.Println("Error(1) trying to read a configuration file. File '", cData.Filename, "' may not already exist...")
return false
}
jConfig := json.NewDecoder(cFile)
jerr := jConfig.Decode(&cData.Data)
if jerr != nil {
panic(jerr)
}
return true
}
使用库配置程序
package main
import (
"fmt"
"./config"
)
// struct basic para configuração
type TestData struct {
URL string
Port string
}
func main() {
var Config config.Configuration
Config.Filename = "config.json"
if !Config.Read(&Config) {
Config.Data = TestData{"http", "8080"}
Config.Create(&Config)
}
fmt.Println(Config.Data)
TestData1 := &TestData{}
TestData1 = Config.Data.(*TestData) // error, why?
fmt.Println(TestData1.URL)
}
新更新:在JimB评论我不清楚某些概念并尝试对其进行回顾之后,我进行了一些更改。 不幸的是,很多事情对我来说还不清楚。 我相信我获得了“大的”理解,但是让我烦恼的是值,格式和指针的“输入”和“输出”,主要是当它进入其他库时。 我还无法遵循它的“完整路径”。
但是,我相信自己的代码有所改进。
我认为我已经纠正了一些观点,但是仍然存在一些大问题:
谢谢
您试图断言Config.Data
的类型为*TestData
,但是您正在将其分配给上面的TestData{"http", "8080"}
。 您可以使用复合文字的地址来创建指针:
Config.Data = &TestData{"http", "8080"}
如果您的配置已经存在,则您的Read
方法将使用默认的json数据类型(可能是map[string]interface{}
填充Data
字段。 如果您首先将正确类型的指针分配给Data
,则它将解码为所需类型。
Config.Data = &TestData{}
回答:由于Data
是interface{}
,因此您永远都不想使用指向该值的指针,因此在编组和解编组时不要使用&
运算符。
您遇到错误的原因是因为您尝试将其解码为interface{}
类型。 在处理JSON对象时,默认情况下,它们会由encoding / json包解码为map[string]interface{}
类型。 这导致类型声明失败,因为map [string] interface {}的内存结构与结构的内存结构大不相同。
更好的方法是使TestData结构成为Configuration结构的预期数据格式:
// Base configuration struct
type Configuration struct {
Filename string
Data *TestData
}
然后,在对文件数据进行解码时,程序包会将数据解组到与最接近的字段和找到的数据匹配的字段中。
如果您需要对数据解组过程进行更多控制,则可以使用struct标签指定将哪些JSON字段解码为哪些struct成员。 您可以在此处阅读有关json struct标签的更多信息: https : //golang.org/pkg/encoding/json/#Marshal
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.