如何通过嵌入接口来嵌入结构值:可组合的结构体

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

How to embed struct values via an embedded interface : Composable Structs

问题

这个问题最好通过一个例子来描述。

http://play.golang.org/p/bQuRr0kV-b

我正在尝试创建一个可组合的结构体。在这个例子中,我想要一个名为Person的类型,它嵌入了Female或Male的值。如果我只是处理结构体,我会像这样嵌入它们:

type Person struct{
  Female
  Male
}

然而,我不能这样做,因为在实际项目中,有很多嵌入的结构体,我更希望保持结构体的清晰和可组合性。但是这里也存在命名冲突 - 在这个例子中,Male和Female都包含字段'Eyes'。将冲突的值移动到Person结构体中不是一个可行的解决方案(因为许多其他嵌入的结构体不包含那个特定的值)。

我希望通过一个简单的接口来传递这些值。示例如下:运行这段代码时,我得到的结果是&{Name: Age:0 Type:male GenderType:0x10434120},其中GenderType是指向Male结构体的指针(在这种情况下)。我的目标是返回一个扁平的结构,看起来像&{Name: Age:0 Type:male Eyes: ChestSize:0}

package main

import "fmt"

type Person struct {
	Name       string
	Age        int
	Type       string
	GenderType GenderType
}

type GenderType interface {
	TypeName() string
}

type Male struct {
	Eyes      string
	ChestSize int
}

type Female struct {
	Eyes     string
	BustSize int
}

func (m *Male) TypeName() string {
	return "male"
}

func (f *Female) TypeName() string {
	return "female"
}

func main() {

	d := NewHuman(new(Male))
	fmt.Printf("%+v", d)
}

func NewHuman(gt GenderType) *Person {
	return &Person{
		Type:       gt.TypeName(),
		GenderType: gt,
	}
}

希望这能帮到你!

英文:

This question is best described by an example

http://play.golang.org/p/bQuRr0kV-b

I am trying to make a composable struct. In this example, I want to have a Person type with embedded values from either Female or Male. If I were just dealing with structs, I would embed them like this

type Person Struct{
  Female
  Male
}

I cannot do this however, both because in the actual project, there are a lot of embedded structs and I would prefer to keep the struct clean and composable. But there is also a naming conflict — in this example, both Male and Female contain the field 'Eyes'. Moving the conflicting value to the Person struct is not a viable solution (as many of the other embedded structs do not contain that particular value).

I was hoping to pass these values via a simple interface. Sample Below: When running this code, I get &{Name: Age:0 Type:male GenderType:0x10434120} where GenderType is the pointer to Male struct(in this case). My Goal is to have a flat structure returned that would look like &{Name: Age:0 Type:male Eyes: ChestSize:0}

package main

import "fmt"

type Person struct {
	Name string
	Age  int
	Type string
	GenderType 
}

type GenderType interface {
	TypeName() string
}

type Male struct {
	Eyes     string
	ChestSize int
}

type Female struct {
	Eyes string
	BustSize int
}

func (m *Male) TypeName() string {
	return "male"
}

func (f *Female) TypeName() string {
	return "female"
}

func main() {

	d := NewHuman(new(Male))
	fmt.Printf("%+v", d)
}

func NewHuman(gt GenderType) *Person {
	return &Person{
		Type: gt.TypeName(),
		GenderType: gt,

	}
}

答案1

得分: 2

我认为在一个扁平的结构中做到这一点是不可能的,因为这将涉及在运行时更改结构类型的内存结构,而Go语言不允许这样做。虽然你可以使用GenderType访问嵌入字段,但这仍然是允许的,因为你是在说这将是一个满足接口的嵌入结构的引用,而不是改变结构本身的结构。

我认为更好的方法是保留嵌入的结构,然后使Person结构成为一个Marshaler。

你可以添加自己的自定义MarshalJSON() (byte[],error)方法,并使用它来生成一个扁平的JSON输出。

如果你需要专门的反序列化,那么你可以使用与Person相关联的(UnmarshalJSON([]byte) error)方法来实现。

请参考https://golang.org/pkg/encoding/json/#Marshaler了解更多信息。

这里有一个示例,展示了我的意思:https://play.golang.org/p/qOl9WSaI3O

英文:

I don't think it is possible to do this in a flat structure because it would entail changing the memory structure of the struct type during runtime, which go doesn't allow. While you can access embedded fields using GenderType, it's still allowed because you are saying that this will be a reference to an embedded struct that satisfies the interface rather than changing the structure of the struct itself.

I think the better way to marshal into a flat json using this is to keep your embedded structure, but then make the Person struct a Marshaler

You can add your own custom MarshalJSON() (byte[],error) method and use this to make a flat json output.

If you need specialized unmarshaling, then you can do likewise with an (UnmarshalJSON([]byte) error) method tied to Person.

see https://golang.org/pkg/encoding/json/#Marshaler for further reference

Here is a playground that shows what I mean: https://play.golang.org/p/qOl9WSaI3O

huangapple
  • 本文由 发表于 2016年3月11日 05:51:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/35928047.html
匿名

发表评论

匿名网友

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

确定