doudouji2016 2016-02-10 22:18
浏览 38

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

I'm new in golang development and have some question regarding something related to this question.

As a learning exercise, I'm trying to create a simple library to handle json based configuration file. As a configuration file to be used for more then one app, it should be able to handle different parameters. Then I have created a type struct Configuration that has the filename and a data interface. Each app will have a struct based on its configuration needs.

In the code bellow, I put all together (lib and "main code") and the "TestData struct" is the "app parameters". If it doesn't exists, it will set a default values and create the file, and it is working. But when I try to read the file. I try to decode the json and put it back into the data interface. But it is giving me an error and I couldn't figure out how to solve this. Can someone help on this?

[updated] I didn't put the targeted code before, because I though that it would be easier to read in in all as a single program. Bellow is the 'targeted code' for better view of the issue. As I will not be able to use the TestData struct inside the library, since it will change from program to program, the only way to handle this was using interface. Is there a better way?

library config

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
}

program using library config

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)
}

NEW UPDATE: I have made some changes after JimB comment about I'm not clear about some concepts and I tried to review it. Sure many things aren't clear for me yet unfortunately. The "big" understanding I believe I got, but what mess my mind up is the "ins" and "outs" of values and formats and pointers, mainly when it goes to other libraries. I'm not able yet to follow the "full path" of it.

Yet, I believe I had some improvement on my code.

I think that I have corrected some points, but still have some big questions:

  1. I stopped sending "Configuration" as a parameter as all "data" were already there as they are "thenselfs" in the instance. Right?
  2. Why do I have use reference in the line 58 (Config.Data = &TestData{})
  3. Why to I have to use pointer in the line 64 (tmp := Config.Data.(*TestData)
  4. Why I CANNOT use reference in line 69 (Config.Data = tmp)

Thanks

  • 写回答

2条回答 默认 最新

  • donglu5000 2016-02-10 22:27
    关注

    You are trying to assert that Config.Data is of type *TestData, but you're assigning it to TestData{"http", "8080"} above. You can take the address of a composite literal to create a pointer:

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

    If your config already exsits, your Read method is going to fill in the Data field with the a default json data type, probably a map[string]interface{}. If you assign a pointer of the correct type to Data first, it will decode into the expected type.

    Config.Data = &TestData{}
    

    Ans since Data is an interface{}, you do not want to ever use a pointer to that value, so don't use the & operator when marshaling and unmarshaling.

    评论

报告相同问题?

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算