我有一个脚本,它根据用户输入从不同的数据源中提取数据,具有通用界面和每个数据源的类型。然后每个数据源都有一个方法来获取该特定源的元数据。我有点难以理解 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)
}
最佳答案
根据细节,我相信您的结构总体上是合理的。但是需要更多的了解。
使用接口(interface),例如Post
,您只能访问为该接口(interface)定义的方法(在本例中为GetMetadata()
) .存储在接口(interface)中的值,例如。 *YouTubeVideo
或 *InstagramPic
) 不能在没有 type assertion 的情况下访问 或 type switch .
因此,无法使用thePost.title
获取标题。
获取帖子的字段值
这里有两种选择(如果算上“类型断言”则为三种):
1) 通过接口(interface)方法添加对属性的访问
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}
最后的说明
通过一些调整,您的结构应该可以使用接口(interface)和类型开关。但具体如何最好地构建它取决于您的具体情况,我们对此知之甚少。
为了更好地理解如何使用界面,我建议阅读: Effective Go: Interfaces and Types
关于使用接口(interface)和动态类型进行变量分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29482343/