How to define dynamic "type struct" in golang?

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

How to define dynamic "type struct" in golang?

问题

这是Playground链接https://play.golang.org/p/qMKxqrOcc2。问题与Playground上的问题类似。

假设我有一个条件需要执行以下操作:

if modelName == "a"{
    model = models.A
} 
else{
    model = models.B
}

其中AB是一些模型:

type A struct{
    filed1 string
    field2 string
    //等等

}

和模型B

type B struct{
    filed1 string
    field2 string
    //等等

}

AB中的字段有一些相同的字段,但大多数反映了数据库表(文档),它们是相同类型的(结构体类型)。

当我在所有这些之前说:

var model interface{}

我得到错误:

type models.A is not an expression

我这样做是为了避免代码中的冗余,如果你问为什么。

问题类似于这个:https://stackoverflow.com/questions/35657362/how-to-return-dynamic-type-struct-in-golang

这是代码的更新:

b := c.mainHelper.GetModelBy("id", id, modelName).(map[string]interface{})
mapstructure.Decode(b, &model)

if modelName == "a"{
    model.Photos = []string{"ph1","ph2"}
}
if modelName == "b"{
    model.Docs = []string{"doc1","doc2"}
}

c.mainHelper.UpdateModel(product, id, modelName)

我知道这很愚蠢,可能不可能做到,但有没有办法做到这一点:

var model models.modelName --> 以某种方式将modelName连接到这个models中?

这是新的更新

我有两个模型Post和Product。它们都有Photos字段。

type Post struct{

    Photos []string
    //等等
}

type Product {

    Photos []string
    //
}

现在我需要一个函数来做到这一点:

func () RemovePhotos(id string, modelName string){

//如果modelName=="post"
    //使用id获取post模型
    
//如果modelName=="product"
    //使用id获取product模型

//设置model.Photos = []string
//在数据库中更新model
}

我知道我不能分配类型,但如何使用这个函数来从不同类型中删除数据?据我所见,代码冗余将如下所示:

func () RemovePhotos(id string, modelName string) return bool{

    if modelName == "post"{

      var model models.Post
      modelWithdata := getModelWithId.(*model)
      modelWithdata.Photos = []string
      //在这里更新数据库中的model
    } 
    if modelName == "product"{
      var model models.Product
      modelWithdata := getModelWithId.(*model)
      modelWithdata.Photos = []string
      //在这里更新数据库中的model
    }

    //我返回什么并不重要,这只是冗余的示例
    return true

}

你可以看到唯一的区别是var model models.Post/var model models.Product
这是代码中的冗余,看起来很丑,但如果没有办法解决这个问题,那么好吧,我将接受这个带有冗余的解决方案。

英文:

Here is Playground link https://play.golang.org/p/qMKxqrOcc2. Problem is similar to one that is on Playground.

Let's say I have a condition and need to do this:

if modelName == "a"{
    model = models.A
} 
else{
    model = models.B
}

where A and B are some models:

type A struct{
    filed1 string
    field2 string
    //etc

}

and model B is

type B struct{
    filed1 string
    field2 string
    //etc

}

Fields in A and B has some same fields but mostly they reflect database table (document) and they are of same type (type struct).

When I say in front of all that:

var model interface{}

I got error:

type models.A is not an expression 

I am doing this to avoid code redundancy in code if you are asking why.

Question is similar to this: https://stackoverflow.com/questions/35657362/how-to-return-dynamic-type-struct-in-golang

Here is update for code:

b := c.mainHelper.GetModelBy("id", id, modelName).(map[string]interface{})
mapstructure.Decode(b, &model)

if modelName == "a"{
    model.Photos = []string{"ph1","ph2"}
}
if modelName == "b"{
    model.Docs = []string{"doc1","doc2"}
}

c.mainHelper.UpdateModel(product, id, modelName)

I know this is stupid and probably is impossible to do but is there and way to do this:

var model models.modelName --> somehow to concat modelName to this models?

HERE IS NEW UPDATE

I have two models Post and Product. Both of them has Photos field.

type Post struct{

    Photos []string
    //etc
}

type Product {

    Photos []string
    //
}

Now I need one function that will say this:

func () RemovePhotos(id string, modelName string){

//if modelName=="post"
    //get model post with id
    
//if modelName=="product"
    //get model product with id

//set model.Photos = []string
//update model in db
}

I can understand that I can not assign type but how to use this one function to remove data from differnt types? As far as I can see code redundancy will look like this:

func () RemovePhotos(id string, modelName string) return bool{

    if modelName == "post"{

      var model models.Post
      modelWithdata := getModelWithId.(*model)
      modelWithdata.Photos = []string
      //update model in db here
    } 
    if modelName == "product"{
      var model models.Product
      modelWithdata := getModelWithId.(*model)
      modelWithdata.Photos = []string
      //update model in db here
    }

    //it does not matter what I return this is just redundancy example
    return true

}

As you can only difference is var model models.Post/var model models.Product.
This is redundancy in code and it looks ugly but if there is no way around this then ok, i will have this one completed with redundancy.

答案1

得分: 6

你不能分配类型,而是要分配实例。你的代码应该如下所示。我在两行代码中添加了注释,你需要更改这两行。

package main

import "fmt"

type B struct {
    field1 string
    field2 string
    // etc
}

type A struct {
    field1 string
    field2 string
    // etc
}

func main() {
    var model interface{}
    modelName := "b"
    if modelName == "a" {
        model = A{} // 注意这里的{}
    } else {
        model = B{} // 同样在这里
    }
    
    fmt.Println(model)
}

只是提个建议,你可能不想使用通用的 interface{} 类型,而是最好使用一个实际的接口,让 AB 都实现它。通用的接口类型会给你带来更多麻烦,而且真正违背了使用静态类型语言如 Go 的目的。

英文:

You can't assign types. You have to assign instances. Your code will effectively have to be the following. I added comments in the two lines that you'll want to change.

package main

import "fmt"

type B struct {
	filed1 string
	field2 string
	//etc

}

type A struct {
	filed1 string
	field2 string
	//etc

}

func main() {
	var model interface{}
	modelName := "b"
	if modelName == "a" {
		model = A{} // note the {} here
	} else {
		model = B{} // same here
	}
    
	fmt.Println(model)
}

Just a word of advice though, you probably don't want to use a generic interface{} type, instead its better to use an actual interface that both A and B implements. The generic interface type will cause you more headaches and really defeats the purpose of using a statically typed language like Go.

答案2

得分: 2

你之所以出现错误,是因为你试图给interface{}实例分配一个类型。你需要给它分配一个实例。

如果你这样写:

var model interface{}

if modelName == "a"{
    model = models.A{}
} 
else{
    model = models.B{}
}

那么它就会正常工作。

英文:

You're getting the error because you're trying to assign a type to the interface{} instance. You need to assign an instance.

If you instead had;

var model interafce{}

if modelName == "a"{
    model = models.A{}
} 
else{
    model = models.B{}
}

then it would work fine.

答案3

得分: 1

这是你的程序,使用了接口类型的实现:

package main

import (
	"log"
)

//// 接口 ////
type PhotoManager interface {
	AddPhotos(id string) (bool, error)
}

//// 帖子 ////
type Post struct {
	Photos []string
}

func (p *Post) AddPhotos(id string) (bool, error) {
	p.Photos = append(p.Photos, id)
	return true, nil
}

//// 产品 ////
type Product struct {
	Photos []string
	Docs   []string
}

func (p *Product) AddPhotos(id string) (bool, error) {
	p.Photos = append(p.Photos, id)
	return true, nil
}

// 用于演示接口使用的无用函数 //
func AddPhotoToInterfaceImplementation(id string, pm PhotoManager) {
	pm.AddPhotos(id)
}

//// 主函数 ////
func main() {
	post := Post{}
	product := Product{}
	post.AddPhotos("123")
	product.AddPhotos("321")
	AddPhotoToInterfaceImplementation("456", &post)
	AddPhotoToInterfaceImplementation("654", &product)
	log.Println(post)
	log.Println(product)
}

这里的关键部分是:

  • PhotoManager 接口类型,用于定义具有通用函数的接口
  • PostProduct 上的 AddPhotos 实现,提供接口函数的实际实现
  • AddPhotoToInterfaceImplementation 函数中的 pm PhotoManager 参数,展示了接口类型的使用方式。
英文:

This is your program from the edit with a interface type implementation:

package main

import (
	"log"
)

//// Interfaces ////
type PhotoManager interface {
	AddPhotos(id string) (bool, error)
}

//// Post ////
type Post struct {
	Photos []string
}

func (p *Post) AddPhotos(id string) (bool, error) {
	p.Photos = append(p.Photos, id)
	return true, nil
}

//// Product ////
type Product struct {
	Photos []string
	Docs   []string
}

func (p *Product) AddPhotos(id string) (bool, error) {
	p.Photos = append(p.Photos, id)
	return true, nil
}

// Useless function to demonstrate interface usage //
func AddPhotoToInterfaceImplementation(id string, pm PhotoManager) {
	pm.AddPhotos(id)
}

//// Main ////
func main() {
	post := Post{}
	product := Product{}
	post.AddPhotos("123")
	product.AddPhotos("321")
	AddPhotoToInterfaceImplementation("456", &post)
	AddPhotoToInterfaceImplementation("654", &product)
	log.Println(post)
	log.Println(product)
}

The moving parts here are:

  • the type PhotoManager interface that is used to define an interface with generic functions
  • the implementations of AddPhotos on Post and Product to provide the actual implementations of the interface functions
  • the usage of pm PhotoManager as parameter to AddPhotoToInterfaceImplementation to show the usage of the interface type.

huangapple
  • 本文由 发表于 2016年4月8日 02:31:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/36484427.html
匿名

发表评论

匿名网友

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

确定