在Golang中,可以像C++一样返回子结构体代替父结构体。

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

Golang return child struct in place of parent like in c++

问题

我正在尝试编写一个通用函数,可以返回多个不同的子对象。目标是能够将它们作为请求 JSON 主体返回。

代码如下:

type GenericType struct {
    V1 string `json:"v1"`
    V2 string `json:"v2"`
}

type SubType struct {
    GenericType
    V3 string `json:"v3"`
}

func TestFunc() GenericType {
    val := SubType{
        GenericType: GenericType{
            V1: "a",
            V2: "b",
        },
        V3: "c",
    }
    return val
}

错误信息为:

无法将 val(类型为 SubType)作为返回参数中的 GenericType 类型使用

是否可能在父指针中返回一个子结构体,而不丢失该子结构体的字段,并将其作为 JSON 对象返回到响应主体中?

英文:

I am trying to have a generic function that can return various multiple child objects. The idea is to be able to return those in a request json body.

The code is as follows

GenericType struct {
	V1 string `json:"v1"`
	V2 string `json:"v2"`
}

SubType struct {
	GenericType
	V3 string `json:"v3"`
}

func TestFunc() GenericType {
	val := SubType{
		GenericType: GenericType{
			V1: "a",
			V2: "b",
		},
		V3: "c",
	}
	return val
}

The error is

cannot use val (type SubType) as type GenericType in return argument

Is it possible to return a descendant struct in a parent pointer without losing the fields of that descendant struct and then return it as a JSON object in response body?

答案1

得分: 3

你不能将嵌入作为继承的替代品,但你可以使用接口来实现类似的功能。代码示例如下:

type Generic interface {
    V1() string
    V2() string
}

type parent struct {
    // ...
}

type child struct {
    // ...
}

// parent
func (p *parent) V1() string {
    return "parent V1"
}

func (p *parent) V2() string {
    return "parent V2"
}

// child
func (c *child) V1() string {
    return "child V1"
}

func (c *child) V2() string {
    return "child V2"
}

// 进一步的子类方法

func NewGeneric() Generic {
    return &parent{}
    // 或者
    // return &child{}
}

以上代码示例中,Generic 是一个接口,定义了 V1()V2() 两个方法。parentchild 分别实现了这个接口。你可以根据需要选择返回 parent 或者 child 的实例作为 NewGeneric() 的结果。

英文:

You can't use embedding as a substitute for inheritance. You could use interfaces for that though. Something like:

type Generic interface {
    V1() string
    V2() string
}

type parent struct {
    // ...
}

type child struct {
    // ...
}

// parent
func (p *parent) V1() string {
    return "parent V1"
}

func (p *parent) V2() string {
    return "parent V2"
}

// child
func (c *child) V1() string {
    return "child V1"
}

func (c *child) V2() string {
    return "child V2"
}

// further child methods

func NewGeneric() Generic {
    return &parent{}
    // or 
    // return &child{}
}

答案2

得分: 1

Go语言没有继承(像C++或Java那样),只有组合和接口。所以你的函数只能返回一个类型的结构体(或指针)或接口。初步可以认为接口与C++中的纯虚类几乎相同。

在你的情况下,接口更好。现在取决于程序的其余部分如何处理返回值。如果需要调用几个方法(在Go语言中,我们更喜欢只有几个方法的接口,最理想的情况是只有一个方法)。

例如:

type GenericType interface {
    getV1() string
    getV2() string
}

但不幸的是,对于所有可以序列化为JSON的对象,我们没有任何公共方法(例如int、string或数组),因此我们必须使用没有公共方法的接口 - interface{}。

英文:

Go does not have inheritance (like C++ or Java), but only composition and interfaces. So your function could return only one type structure (or pointer) or interface. As a first approximation you could think that interface is nearly the same as pure abstract class in C++).

In your case interface is better. And now it depends how rest of the program will work with returned value. If it need to call a few methods (in go we prefer interface with only few method - ideal is one).

Eg.

type GenericType interface {
    getV1() string
    getV2() string
}

But unfortunately - for all object that could be serialized into JSON we don't have any common method (eg. int, string or arrays), therefore we have to use interface with no common method - interface{}.

答案3

得分: 0

嵌入

在Go语言中,嵌入(embedding)不允许继承属性(因为它不是继承)。当你将一个结构体嵌入到另一个结构体中时,你是将其方法(而不是属性)组合到一个新的组合中。

> Go语言没有提供典型的、基于类型的子类化概念,但它确实可以通过在结构体或接口中嵌入类型来“借用”实现的一部分。

接口

Go语言提供了接口来实现泛型类型,并提供类型断言来访问具体类型及其属性。

Playground

type generic interface {
    say() string
}

type type1 struct {
    msg string
}

func (t type1) say() string {
    return t.msg
}

type type2 struct{}

func (t type2) say() string {
    return "I'm type 2"
}

func main() {
    t1 := type1{"Hey! I'm type1"}
    t2 := type2{}

    tl := []generic{t1, t2}

    for _, i := range tl {
        switch v := i.(type) {
        case type1:
            fmt.Println(v.say())
            fmt.Println(v.msg)
        case type2:
            fmt.Println(v.say())
            // fmt.Println(v.msg) Uncomment to see that type2 has no msg attribute.
        }
    }
}
英文:

Embedding

Embedding in Go doesn't allow to inherit (since it is not inheritance) attributes. When you are embedding one struct to another you are composing its' methods (not attributes) to a new composition.

> Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.

Interfaces

Go provides <strike>awesome</strike> interfaces to implement generic types and type assertion to have access to concrete types and its' attributes.

Plyground:

type generic interface {
    say() string
}

type type1 struct {
    msg string
}

func (t type1) say() string {
    return t.msg
}

type type2 struct{}

func (t type2) say() string {
    return &quot;I&#39;m type 2&quot;
}

func main() {
    t1 := type1{&quot;Hey! I&#39;m type1&quot;}
	t2 := type2{}

    tl := []generic{t1, t2}

	for _, i := range tl {
    	switch v := i.(type) {
	    case type1:
		    fmt.Println(v.say())
			fmt.Println(v.msg)
    	case type2:
	    	fmt.Println(v.say())
		    // fmt.Println(v.msg) Uncomment to see that type2 has no msg attribute.
		}
    }
}

huangapple
  • 本文由 发表于 2017年3月3日 15:01:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/42572623.html
匿名

发表评论

匿名网友

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

确定