如何动态创建对象?

我想要根据配置文件,来动态的创建对象,举例如下:

配置文件: message.xml

<xml>
    <message name="login">
    <var  name="username" type="string" sizelimit=32> </var>
    <var  name="password"  type="string" sizelimit=32> </var>
    </message>
</xml>

OK ,我的想法就是,想要根据 message.xml,动态的生成我的消息类型 这样,我只需要配置一些xml文件就行了,不用写大量的 go 代码文件来定义消息 如果我自己写 go代码文件,可能就写成下面这样了:

type message_login struct { username string password string }

func (m *message_login) Read() { //xxxxx }

func (m *message_login) Write() { //xxxxx }


我想问的是,有没有一种办法,可以自动生成类似的 go 代码文件?

共 3 个回复


perki

自己写个go源码生成器咯。。也不难

# 0

fanyang

看到有点晚,希望帮助其他,可扩展生成任何所需文件

// test.go
package main

import (
    "encoding/xml"
    "html/template"
    "io/ioutil"
    "os"
    "os/exec"
)

type (
    Var struct {
        Name      string `xml:"name,attr"`
        Type      string `xml:"type,attr"`
        Sizelimit string `xml:"sizelimit,attr"`
    }
    Message struct {
        Name string `xml:"name,attr"`
        Vars []Var  `xml:"var"`
    }
    Xml struct {
        XMLName xml.Name `xml:"xml"`
        Message Message  `xml:"message"`
    }
)

const (
    fileName = "./message.go"
    cfgName  = "./message.xml"
    tplName  = "./message.tpl"
)

func main() {
    //解析配置文件
    cfgData, err := ioutil.ReadFile(cfgName)
    if err != nil {
        panic(err)
    }
    var x Xml
    err = xml.Unmarshal(cfgData, &x)
    if err != nil {
        panic(err)
    }
    //加载模板文件
    tplData, err := ioutil.ReadFile(tplName)
    if err != nil {
        panic(err)
    }
    msg := template.Must(template.New("message").Parse(string(tplData)))

    file, err := os.Create(fileName)
    if err != nil {
        panic(err)
    }
    defer file.Close()
    //用模板生成go文件
    err = msg.Execute(file, x)
    if err != nil {
        os.Remove(fileName)
        panic(err)
    }
    //自动格式化并且导入需要的包
    cmd := exec.Command("goimports", "-w", fileName)
    err = cmd.Run()
    if err != nil {
        os.Remove(fileName)
        panic(err)
    }
}
// message.xml
<xml>
 <message name="login">
  <var  name="username" type="string" sizelimit="32">
  </var>
  <var  name="password"  type="string" sizelimit="32">
  </var>
 </message>
</xml>
// message.tpl
package message

type message_{{.Message.Name}} struct { 
    {{range .Message.Vars}}{{.Name}} {{.Type}}
    {{end}}
}

func (m *message_{{.Message.Name}}) Read() { 
    {{range .Message.Vars}} fmt.Println(m.{{.Name}}) 
    {{end}}
}

func (m *message_{{.Message.Name}}) Write() { 
    {{range .Message.Vars}} m.{{.Name}}="hello" 
    {{end}}
}
// message.go
package message

import "fmt"

type message_login struct {
    username string
    password string
}

func (m *message_login) Read() {
    fmt.Println(m.username)
    fmt.Println(m.password)

}

func (m *message_login) Write() {
    m.username = "hello"
    m.password = "hello"

}
# 2