How to pass data struct as parameter in golang

huangapple go评论89阅读模式
英文:

How to pass data struct as parameter in golang

问题

XML转JSON

package main

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
)

type Persons struct {
	Person []struct {
		Name string
		Age  int
	}
}
type Places struct {
	Place []struct {
		Name    string
		Country string
	}
}

type Parks struct {
	Park struct {
		Name     []string
		Capacity []int
	}
}

const personXml = `
	<Persons>
		<Person><Name>Koti</Name><Age>30</Age></Person>
		<Person><Name>Kanna</Name><Age>29</Age></Person>
	</Persons>
`

const placeXml = `
	<Places>
		<Place><Name>Chennai</Name><Country>India</Country></Place>
		<Place><Name>London</Name><Country>UK</Country></Place>
	</Places>
`

const parkXml = `
	<Parks>
		<Park><Name>National Park</Name><Capacity>10000</Capacity></Park>
		<Park>Asian Park</Name><Capacity>20000</Capacity></Park>
	</Parks>
`

func WhatIamUsing() {
	var persons Persons
	xml.Unmarshal([]byte(personXml), &persons)
	per, _ := json.Marshal(persons)
	fmt.Printf("%s\n", per)

	var places Places
	xml.Unmarshal([]byte(placeXml), &places)
	pla, _ := json.Marshal(places)
	fmt.Printf("%s\n", pla)

	var parks Parks
	xml.Unmarshal([]byte(parkXml), &parks)
	par, _ := json.Marshal(parks)
	fmt.Printf("%s\n", par)
}

func Xml2Json(xmlString string, dataStruct interface{}) (jsobj string, err error) {
	xml.Unmarshal([]byte(xmlString), &dataStruct)
	js, _ := json.Marshal(dataStruct)
	return fmt.Sprintf("%s\n", js), nil
}

func main() {
	jsonstring, _ := Xml2Json(personXml, Persons{})
	fmt.Println(jsonstring)
}

错误信息:

prog.go:73: DataStruct不是一个类型

prog.go:80: 类型Persons不是一个表达式

goplay链接:http://play.golang.org/p/vayb0bawKx

英文:

XML to Json

package main
import (
&quot;encoding/json&quot;
&quot;encoding/xml&quot;
&quot;fmt&quot;
)
type Persons struct {
Person []struct {
Name string
Age  int
}
}
type Places struct {
Place []struct {
Name    string
Country string
}
}
type Parks struct {
Park struct {
Name     []string
Capacity []int
}
}
const personXml = `
&lt;Persons&gt;
&lt;Person&gt;&lt;Name&gt;Koti&lt;/Name&gt;&lt;Age&gt;30&lt;/Age&gt;&lt;/Person&gt;
&lt;Person&gt;&lt;Name&gt;Kanna&lt;/Name&gt;&lt;Age&gt;29&lt;/Age&gt;&lt;/Person&gt;
&lt;/Persons&gt;
`
const placeXml = `
&lt;Places&gt;
&lt;Place&gt;&lt;Name&gt;Chennai&lt;/Name&gt;&lt;Country&gt;India&lt;/Country&gt;&lt;/Place&gt;
&lt;Place&gt;&lt;Name&gt;London&lt;/Name&gt;&lt;Country&gt;UK&lt;/Country&gt;&lt;/Place&gt;
&lt;/Places&gt;
`
const parkXml = `
&lt;Parks&gt;
&lt;Park&gt;&lt;Name&gt;National Park&lt;/Name&gt;&lt;Capacity&gt;10000&lt;/Capacity&gt;&lt;/Park&gt;
&lt;Park&gt;Asian Park&lt;/Name&gt;&lt;Capacity&gt;20000&lt;/Capacity&gt;&lt;/Park&gt;
&lt;/Parks&gt;
`
func WhatIamUsing() {
var persons Persons
xml.Unmarshal([]byte(personXml), &amp;persons)
per, _ := json.Marshal(persons)
fmt.Printf(&quot;%s\n&quot;, per)
var places Places
xml.Unmarshal([]byte(placeXml), &amp;places)
pla, _ := json.Marshal(places)
fmt.Printf(&quot;%s\n&quot;, pla)
var parks Parks
xml.Unmarshal([]byte(parkXml), &amp;parks)
par, _ := json.Marshal(parks)
fmt.Printf(&quot;%s\n&quot;, par)
}

What i want is a generic function which takes xml string and dataStruct
and returns a Json output. But below function is throwing an error
How to impliment this?

func Xml2Json(xmlString string, DataStruct interface{}) (jsobj string, err error) {
var dataStruct DataStruct
xml.Unmarshal([]byte(personXml), &amp;dataStruct)
js, _ := json.Marshal(dataStruct)
return fmt.Sprintf(&quot;%s\n&quot;, js), nil
}
func main() {
jsonstring, _ := Xml2Json(personXml, Persons)
}

Error message:

prog.go:73: DataStruct is not a type

prog.go:80: type Persons is not an expression

goplay link: http://play.golang.org/p/vayb0bawKx

答案1

得分: 13

你不能将一个类型(比如Persons)存储在一个接口中。你可以将reflect.Type传递给你的函数。然后,你的调用会像这样:Xml2Json(personXml, reflect.TypeOf(Persons)),我认为这样写很丑陋。

更好的方法可能是:

func Xml2Json(xmlString string, value interface{}) (string, error) {
    if err := xml.Unmarshal([]byte(xmlString), value); err != nil {
        return "", err
    }
    js, err := json.Marshal(value)
    if err != nil {
        return "", err
    }
    return string(js), nil
}

如果你只对值本身不感兴趣,你可以使用Xml2Json(personXml, new(Persons))来调用这个函数,如果你还想获取结构体值以供以后处理,你可以使用:

var persons Persons
Xml2Json(personXML, &persons)
英文:

You can not store a type (like Persons) in an interface. You could pass a reflect.Type to your function. Then, your call would look like Xml2Json(personXml, reflect.TypeOf(Persons)) which is quite ugly in my opinion.

The better approach is probably:

func Xml2Json(xmlString string, value interface{}) (string, error) {
if err := xml.Unmarshal([]byte(xmlString), value); err != nil {
return &quot;&quot;, err
}
js, err := json.Marshal(value)
if err != nil {
return &quot;&quot;, err
}
return string(js), nil
}

You can use this function with Xml2Json(personXml, new(Persons)) if you are not interested in the value itself, and

var persons Persons
Xml2Json(personXML, &amp;persons)

when you also want to retrieve the struct value for later processing.

答案2

得分: 1

Xml2Json函数声明了一个名为DataStruct的参数。在同一作用域中,标识符DataStruct不能表示类型名称。如果你想在同一作用域中使用类型名称DataStruct,你必须给你的参数取一个不同的名字。

main函数中的问题是函数调用语法在括号内期望一个表达式列表。你在那里传递的是一个_类型名称_,显然不能是一个表达式。

所以回答你的问题:不,你不能将类型作为参数传递给函数。但是你可以传递一个类型的实例(在这种情况下是指向这种实例的指针),以获得你想要的效果:

package main

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"log"
)

type Persons struct {
	Person []struct {
		Name string
		Age  int
	}
}

type Places struct {
	Place []struct {
		Name    string
		Country string
	}
}

type Parks struct {
	Park struct {
		Name     []string
		Capacity []int
	}
}

const (
	personXml = `
        <Persons>
            <Person><Name>Koti</Name><Age>30</Age></Person>
            <Person><Name>Kanna</Name><Age>29</Age></Person>
        </Persons>
    `
	placeXml = `
        <Places>
            <Place><Name>Chennai</Name><Country>India</Country></Place>
            <Place><Name>London</Name><Country>UK</Country></Place>
        </Places>
    `

	parkXml = `
        <Parks>
            <Park><Name>National Park</Name><Capacity>10000</Capacity></Park>
            <Park><Name>Asian Park</Name><Capacity>20000</Capacity></Park>
        </Parks>
    `
)

func Xml2Json(xmlString string, DataStruct interface{}) (jsobj string, err error) {
	if err = xml.Unmarshal([]byte(xmlString), DataStruct); err != nil {
		return
	}

	js, err := json.Marshal(DataStruct)
	if err != nil {
		return
	}

	return fmt.Sprintf("%s", js), nil
}

func main() {
	var p Persons
	jsonstring, err := Xml2Json(personXml, &p)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(jsonstring)

	var q Places
	jsonstring, err = Xml2Json(placeXml, &q)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(jsonstring)

	var r Parks
	jsonstring, err = Xml2Json(parkXml, &r)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(jsonstring)

}

输出:

{"Person":[{"Name":"Koti","Age":30},{"Name":"Kanna","Age":29}]}
{"Place":[{"Name":"Chennai","Country":"India"},{"Name":"London","Country":"UK"}]}
{"Park":{"Name":["National Park","Asian Park"],"Capacity":[10000,20000]}}

Playground

英文:

The function Xml2Json declares a parameter named DataStruct. In the same scope the identifier DataStruct cannot denote a type name. If you want to use the type name DataStruct within the same scope, you must name your parameter differently.

In the main function the problem is that a function call syntax expects an expression list within the parenthesis. There you're passing a type name, which clearly cannot be an expression.

So to answer your question: No, you cannot pass a type as an argument to a function. But you can pass an instance of a type (in this case a pointer to such instance) to get the effect you're about:

package main
import (
&quot;encoding/json&quot;
&quot;encoding/xml&quot;
&quot;fmt&quot;
&quot;log&quot;
)
type Persons struct {
Person []struct {
Name string
Age  int
}
}
type Places struct {
Place []struct {
Name    string
Country string
}
}
type Parks struct {
Park struct {
Name     []string
Capacity []int
}
}
const (
personXml = `
&lt;Persons&gt;
&lt;Person&gt;&lt;Name&gt;Koti&lt;/Name&gt;&lt;Age&gt;30&lt;/Age&gt;&lt;/Person&gt;
&lt;Person&gt;&lt;Name&gt;Kanna&lt;/Name&gt;&lt;Age&gt;29&lt;/Age&gt;&lt;/Person&gt;
&lt;/Persons&gt;
`
placeXml = `
&lt;Places&gt;
&lt;Place&gt;&lt;Name&gt;Chennai&lt;/Name&gt;&lt;Country&gt;India&lt;/Country&gt;&lt;/Place&gt;
&lt;Place&gt;&lt;Name&gt;London&lt;/Name&gt;&lt;Country&gt;UK&lt;/Country&gt;&lt;/Place&gt;
&lt;/Places&gt;
`
parkXml = `
&lt;Parks&gt;
&lt;Park&gt;&lt;Name&gt;National Park&lt;/Name&gt;&lt;Capacity&gt;10000&lt;/Capacity&gt;&lt;/Park&gt;
&lt;Park&gt;&lt;Name&gt;Asian Park&lt;/Name&gt;&lt;Capacity&gt;20000&lt;/Capacity&gt;&lt;/Park&gt;
&lt;/Parks&gt;
`
)
func Xml2Json(xmlString string, DataStruct interface{}) (jsobj string, err error) {
if err = xml.Unmarshal([]byte(xmlString), DataStruct); err != nil {
return
}
js, err := json.Marshal(DataStruct)
if err != nil {
return
}
return fmt.Sprintf(&quot;%s&quot;, js), nil
}
func main() {
var p Persons
jsonstring, err := Xml2Json(personXml, &amp;p)
if err != nil {
log.Fatal(err)
}
fmt.Println(jsonstring)
var q Places
jsonstring, err = Xml2Json(placeXml, &amp;q)
if err != nil {
log.Fatal(err)
}
fmt.Println(jsonstring)
var r Parks
jsonstring, err = Xml2Json(parkXml, &amp;r)
if err != nil {
log.Fatal(err)
}
fmt.Println(jsonstring)
}

Playground


Output:

{&quot;Person&quot;:[{&quot;Name&quot;:&quot;Koti&quot;,&quot;Age&quot;:30},{&quot;Name&quot;:&quot;Kanna&quot;,&quot;Age&quot;:29}]}
{&quot;Place&quot;:[{&quot;Name&quot;:&quot;Chennai&quot;,&quot;Country&quot;:&quot;India&quot;},{&quot;Name&quot;:&quot;London&quot;,&quot;Country&quot;:&quot;UK&quot;}]}
{&quot;Park&quot;:{&quot;Name&quot;:[&quot;National Park&quot;,&quot;Asian Park&quot;],&quot;Capacity&quot;:[10000,20000]}}

huangapple
  • 本文由 发表于 2013年8月15日 16:27:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/18248898.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定