我有一个脚本来自不同的数据源,具体取决于用户输入,具有通用接口和每个数据源的类型。然后,每个数据源都有一个方法来获取该特定源的元数据。我正在努力理解 idomatic Go实现以根据输入切换类型。
这个例子没有编译,但它是最能说明我想要做的事情的版本:
type Post interface {
GetMetadata() bool
}
type YouTubeVideo struct {
ID string
Title string
ChannelID string
ChannelTitle string
PublishedAt string
}
func (ig *YouTubeVideo) GetMetadata() bool {
// ...
}
type InstagramPic struct {
ID string
ShortCode string
Type string
Title string
PublishedAt string
}
func (ig *InstagramPic) GetMetadata() bool {
// ...
}
func main() {
var thePost Post
switch domain {
case "youtube":
thePost = new(YouTubeVideo)
thePost.ID = pid
case "instagram":
thePost = new(InstagramPic)
thePost.ShortCode = pid
}
thePost.GetMetadata()
fmt.Println(thePost.title)
}
答案 0 :(得分:1)
根据细节,我相信您的结构通常是合理的。但需要更多的理解。
使用Post
等界面,您只能访问为界面定义的方法(在本例中为GetMetadata()
)。存储在界面中的值,例如。如果没有 type assertion 或 type switch ,则无法访问*YouTubeVideo
或*InstagramPic
。
因此,无法使用thePost.title
获取标题。
获取帖子的字段值
这里有两种选择(如果算上“类型断言”,则有三种选择):
1)通过接口方法添加对属性的访问
type Post interface {
GetMetadata() bool
Title() string // Added Title method
}
func (ig *YouTubeVideo) Title() string {
return ig.Title
}
...
fmt.Println(thePost.Title())
2)使用类型开关
访问属性switch v := thePost.(type) {
case *YouTubeVideo:
fmt.Println(v.ChannelTitle)
case *InstagramPic:
fmt.Println(v.PublishedAt)
}
如果实现Post
的所有类型都应该授予对某个属性的访问权限,那么备选方案1)非常有用。 2)允许您访问特定于该类型的字段,但它需要每种类型的大小写。
设置帖子的字段值
就像获取时一样,您无法直接设置Interface值的字段。在这种情况下,您应首先设置所需的字段,然后将其存储在界面中:
v := new(YouTubeVideo)
v.ID = pid
thePost = v // Store the *YouTubeVideo in thePost
或者更短一些:
thePost = &YouTubeVideo{ID: pid}
最后的注释
通过一些调整,您的结构应该使用接口和类型开关。但究竟如何最好地构建它取决于您的具体情况,我们的信息太少。
为了更好地了解如何使用界面,我建议您阅读: Effective Go: Interfaces and Types