从同一个函数返回不同的专门实现接口的方法

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

Return different specialised implementations of interfaces from the same function

问题

我有几个数据结构,它们之间有一些相似但具有各自独特字段的特点。它们都实现了相同的行为接口(DataPoint)。因此,可以通过在接口定义的方法上操作并交换每个结构的类型来进行它们的处理。我想要一个函数根据某些条件为每种类型返回一个空的数据结构。然而,如果我的函数按照接口的签名返回接口,但实际上返回的是一个实现,编译器会报错。

这里是一个简化的示例和Playground样例,展示了我的意思:

package main

import "fmt"

type DataPoint interface {
	Create()
}

type MetaData struct {
	UniqueId  string
	AccountId int
	UserId    int
}

type Conversion struct {
	Meta  MetaData
	Value int
}

func (c *Conversion) Create() {
	fmt.Println("CREATE Conversion")
}

type Impression struct {
	Meta  MetaData
	Count int
}

func (i *Impression) Create() {
	fmt.Println("CREATE Impression")
}

func getDataPoint(t string) DataPoint {
	if t == "Conversion" {
		return &Conversion{}
	} else {
		return &Impression{}
	}
}

func main() {
	meta := MetaData{
		UniqueId:  "ID123445X",
		AccountId: 1,
		UserId:    2,
	}
	dpc := getDataPoint("Conversion")
	dpc.Meta = meta
	dpc.Value = 100
	dpc.Create()

	fmt.Println(dpc)

	dpi := getDataPoint("Impression")
	dpi.Meta = meta
	dpi.Count = 42
	dpi.Create()

	fmt.Println(dpi)
}

编译产生以下错误:

prog.go:51: dpc.Meta undefined (type DataPoint has no field or method Meta)
prog.go:52: dpc.Value undefined (type DataPoint has no field or method Value)
prog.go:58: dpi.Meta undefined (type DataPoint has no field or method Meta)
prog.go:59: dpi.Count undefined (type DataPoint has no field or method Count)
英文:

I'm have a few data structures which are similar with some unique fields to each. They all implement the same behavioural interface (DataPoint).
Therefore their processing can be done once while exchanging the type of each structure and operating on it via the methods defined in the interface. I wanted to have a function return me the empty data struct for each type based on some criteria.
However, I can't seem to compile this as if my function returns the interface by signature but actually returns an implementation, it complains.

Here's a simplified example and playground sample of what I mean:

https://play.golang.org/p/LxY55BC59D

package main

import "fmt"


type DataPoint interface {
	Create() 
}

type MetaData struct {
	UniqueId string
	AccountId int
	UserId int
}

type Conversion struct {
	Meta MetaData
	Value int
}

func (c *Conversion) Create() {
	fmt.Println("CREATE Conversion")
}
 
type Impression struct {
	Meta MetaData
	Count int
}

func (i *Impression) Create() {
	fmt.Println("CREATE Impression")
} 

func getDataPoint(t string) DataPoint {
	if t == "Conversion" {
		return &Conversion{}
	} else {
		return &Impression{}
	}
}



func main() {
	meta := MetaData{
		UniqueId: "ID123445X",
		AccountId: 1,
		UserId: 2,
	}
	dpc := getDataPoint("Conversion")
	dpc.Meta = meta
	dpc.Value = 100
	dpc.Create()

	fmt.Println(dpc)

	dpi := 	getDataPoint("Impression")
	dpi.Meta = meta
	dpi.Count = 42
	dpi.Create()

	fmt.Println(dpi)
	
}

The compilation produces:

prog.go:51: dpc.Meta undefined (type DataPoint has no field or method Meta)
prog.go:52: dpc.Value undefined (type DataPoint has no field or method Value)
prog.go:58: dpi.Meta undefined (type DataPoint has no field or method Meta)
prog.go:59: dpi.Count undefined (type DataPoint has no field or method Count)

答案1

得分: 7

你可以使用类型断言(type assertion)来访问这样的字段。你只能在接口上调用方法,它对实现细节一无所知。如果你确实需要访问这些字段,可以使用类型断言:

dpc := getDataPoint("Conversion")
dpc.(*Conversion).Meta = meta
dpc.(*Conversion).Value = 100
dpc.Create()

dpi := getDataPoint("Impression")
dpi.(*Impression).Meta = meta
dpi.(*Impression).Count = 42
dpi.Create()

Playground: https://play.golang.org/p/Ije8hfNcWS

英文:

You can't access fields like that without a type assertion. You can only call methods on the interface, it doesn't know anything about its implementation details. If you do need to access those fields, use a type assertion:

dpc := getDataPoint("Conversion")
dpc.(*Conversion).Meta = meta
dpc.(*Conversion).Value = 100
dpc.Create()

dpi := getDataPoint("Impression")
dpi.(*Impression).Meta = meta
dpi.(*Impression).Count = 42
dpi.Create()

Playground: https://play.golang.org/p/Ije8hfNcWS.

答案2

得分: 3

你的问题是getDataPoint的结果是一个DataPoint,它只有一个可用的方法:Create。然后你尝试将其用作特定的结构类型,这些结构类型恰好提供了所有的元数据字段。

你可以让DataPoint接口提供一个MetaData函数或类似的方法,或者在字段上提供单独的getter方法。如果MetaData类型实现了这些方法,当将其作为接口本身呈现时,这些方法将在任何特定的结构体中都可用。

英文:

Your issue is that the result from getDataPoint is a DataPoint, which only has one method available: Create. You then try to use it as the specific struct types, which incidentally provide all of the metadata fields.

You could have your DataPoint interface provide a MetaData function or something like that, or individual getters on the fields. If the MetaData type implements those methods they will be available from either of the specific structs when presented as the interface itself.

答案3

得分: 2

你的函数getDataPoint返回一个接口,而不是一个结构体。所以如果你想将其返回值用作结构体,你必须先进行类型断言。这里是一个可工作的代码示例:
https://play.golang.org/p/5lx4BLhQBg

英文:

Your function getDataPoint returns an interface, not a struct. So if you want to use its return value as a struct, you must do a type assertion first. Here is a working code :
https://play.golang.org/p/5lx4BLhQBg

huangapple
  • 本文由 发表于 2015年11月3日 23:50:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/33503417.html
匿名

发表评论

匿名网友

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

确定