将`struct`作为函数参数的类型名传递

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

Pass `struct` as type name to function argument

问题

我正在使用Go语言编写一种基于RESTful API的对象关系映射器(ORM)。我计划在完成后将其授权为MIT许可证。这个想法是使用第三方REST API作为数据存储,而golang客户端将查询所需的数据。

API的响应是具有已知结构的JSON。

这是我的代码:

type AClient struct {
    Id        string `json:"id"`
    Uid       string `json:"uid"`
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    CreatedAt string `json:"createdAt"`
    UpdatedAt string `json:"updatedAt"`
    City      string `json:"city"`
    Address   string `json:"address"`
    Telefone  string `json:"telefone"`
    Zip       string `json:"zip"`
    Telefon   string `json:"telefon"`
    Comment   string `json:"comment"`
}

type AEvents struct {
    Id          string    `json:"id"`
    Security    bool      `json:"security"`
    Description string    `json:"description"`
    Good        AGood     `json:"good"`
    Client      AClient   `json:"client"`
    Author      AAuthor   `json:"author"`
    InFuture    bool      `json:"inFuture"`
    CreatedAt   time.Time `json:"createdAt"`
    UpdatedAt   time.Time `json:"updatedAt"`
}

type Entry struct {
    AEvents //在需要时必须更改为`AClients`
}

type ORM struct {
    ApiUrl         string
    ModelName      string
    ModelInterface Entry
    HuntKey        string
    HuntSid        string
    Csrf           string
}

func (o *ORM) Query(parameters map[string]string) ([]Entry, AMetadata, error) {
    // ...
}

当实例化ORM对象时,如何传递要用于解析JSON响应的结构体名称?当前的代码使用AEvents结构体,但我希望它可以轻松地更改为AClient等。

更新:
我已经审查了https://github.com/jinzhu/gorm的代码,并发现了很多可以实现的东西。正如我承诺的那样,我将这段代码发布为开源项目-https://github.com/vodolaz095/hrorm

英文:

I'm writing some sort of RESTfull API based Object relational mapper in go.
I plan to make it MIT licensed, when i finish it.
The idea is to use some 3rd party REST API as data storage, and the golang client will query it for data needed.

The API responses are JSONs with known structure.

this is my code:

type AClient struct {
	Id        string `json:"id"`
	Uid       string `json:"uid"`
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	CreatedAt string `json:"createdAt"`
	UpdatedAt string `json:"updatedAt"`
	City      string `json:"city"`
	Address   string `json:"address"`
	Telefone  string `json:"telefone"`
	Zip       string `json:"zip"`
	Telefon   string `json:"telefon"`
	Comment   string `json:"comment"`
}

type AEvents struct {
	Id          string    `json:"id"`
	Security    bool      `json:"security"`
	Description string    `json:"description"`
	Good        AGood     `json:"good"`
	Client      AClient   `json:"client"`
	Author      AAuthor   `json:"author"`
	InFuture    bool      `json:"inFuture"`
	CreatedAt   time.Time `json:"createdAt"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

type Entry struct {
	AEvents //this have to be changed to `AClients` in runtime when needed
}

type ORM struct {
	ApiUrl         string
	ModelName      string
	ModelInterface Entry
	HuntKey        string
	HuntSid        string
	Csrf           string
}

func (o *ORM) Query(parameters map[string]string) ([]Entry, AMetadata, error) {
	responseParsed := struct {
		Status   string    `json:"status"`
		Metadata AMetadata `json:"metadata"`
		Data     []Entry   `json:"data"` //todo - use o.ModelInterface
	}{}
	client := &http.Client{}

	var queryString string

	for k, v := range parameters {
		queryString = queryString + fmt.Sprintf("%v=%v&", url.QueryEscape(k), url.QueryEscape(v))
	}

	req, err := http.NewRequest("GET", fmt.Sprintf("%v%v?%v", o.ApiUrl, o.ModelName, queryString), nil)
	fmt.Println("---------------------------------------------")
	fmt.Println(fmt.Sprintf("[GET] %v%v?%v", o.ApiUrl, o.ModelName, queryString))
	req.Header.Set("huntKey", o.HuntKey)
	if err != nil {
		return nil, AMetadata{}, err
	}
	res, err1 := client.Do(req)
	defer res.Body.Close()
	if err1 != nil {
		return nil, AMetadata{}, err1
	}
	if res.StatusCode == 200 {
		for _, v := range res.Cookies() {
			if v.Name == "XSRF-TOKEN" {
				o.Csrf = v.Value
			}
			if v.Name == "hunt.sid" {
				o.HuntSid = v.Value
			}
		}
		fmt.Printf("CSRF %v\n", o.Csrf)
		fmt.Printf("HuntSid %v\n", o.HuntSid)
		fmt.Println("---------------------------------------------")
		raw, err2 := ioutil.ReadAll(res.Body)
		if err2 != nil {
			return nil, AMetadata{}, err2
		} else {
			err2 = json.Unmarshal(raw, &responseParsed)
			return responseParsed.Data, responseParsed.Metadata, nil
		}
	} else {
		return nil, AMetadata{}, errors.New("Unable to fetch data!")
	}
}

How can I make this:
When instantiating the ORM object, how can i pass the struct name, that will be used to parse the JSON response. The current code works with the struct of AEvents, but i want it to be easy changeble t AClient and so on.

UPD:
i have reviewed the code of https://github.com/jinzhu/gorm and find out tons of things how can i implement it.
Than, as i have promised, I publish this code as open source -https://github.com/vodolaz095/hrorm

答案1

得分: 1

你可以使用反射,但要注意它并不简单,并且相对较慢。我不知道其他的方法。

最简单的方法是将参数的类型设置为interface{},并传入一个空的(未初始化的)结构体实例,用于解组。我强烈建议阅读我列出的两个链接中的第二个链接——它提供了关于反射的清晰介绍,以及如何使用反射解决类似这个问题的方法。

英文:

You can use reflection, but be warned that it is non-trivial and relatively slow. I don't know of any other way.

The simplest way to do this is to make your parameter of type interface{} and pass in an empty (uninitialized) instance of the struct you wish to unmarshal into. I highly suggest reading the second of the two links I list - it provides a clear introduction to reflection and how to use it for solving problems like this one.

huangapple
  • 本文由 发表于 2015年2月5日 03:38:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/28329938.html
匿名

发表评论

匿名网友

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

确定