繁体   English   中英

我该怎么做呢? 获取结构以接口的形式发送到func并将其作为结构返回?

[英]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评论我不清楚某些概念并尝试对其进行回顾之后,我进行了一些更改。 不幸的是,很多事情对我来说还不清楚。 我相信我获得了“大的”理解,但是让我烦恼的是值,格式和指针的“输入”和“输出”,主要是当它进入其他库时。 我还无法遵循它的“完整路径”。

但是,我相信自己的代码有所改进。

我认为我已经纠正了一些观点,但是仍然存在一些大问题:

  1. 我停止发送“配置”作为参数,因为所有“数据”已经存在,因为它们是实例中的“自己”。 对?
  2. 为什么在第58行中使用引用(Config.Data =&TestData {})
  3. 为什么我必须在第64行中使用指针(tmp:= Config.Data。(* TestData)
  4. 为什么我不能在第69行中使用引用(Config.Data = tmp)

谢谢

您试图断言Config.Data的类型为*TestData ,但是您正在将其分配给上面的TestData{"http", "8080"} 您可以使用复合文字的地址来创建指针:

Config.Data = &TestData{"http", "8080"}

如果您的配置已经存在,则您的Read方法将使用默认的json数据类型(可能是map[string]interface{}填充Data字段。 如果您首先将正确类型的指针分配给Data ,则它将解码为所需类型。

Config.Data = &TestData{}

回答:由于Datainterface{} ,因此您永远都不想使用指向该值的指针,因此在编组和解编组时不要使用&运算符。

您遇到错误的原因是因为您尝试将其解码为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM