dtutlamjasblef7982 2015-04-07 01:39
浏览 22
已采纳

使用接口和动态类型进行变量分配

I have a script that pulls from a different data source depending on the user input with a general interface and a type for each data source. Each data source then has a method to get the meta data for that particular source. I'm struggling a bit understanding the idomatic Go implementation to switch types depending on input.

This example does not compile, but it was the version that best illustrates what I want to do:

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)
}
  • 写回答

1条回答 默认 最新

  • duanchu2607 2015-04-07 12:35
    关注

    Depending on the details, I believe your structure is in general sound. But some more understanding is required.

    With an interface, such as Post, you can only access the methods defined for the interface (GetMetadata() in this case). The value stored in the interface, eg. the *YouTubeVideo or *InstagramPic) cannot be accessed without a type assertion or type switch.

    Therefore, it is not possible to get the title using thePost.title.

    Getting a Post's field value

    Here you have two alternatives (three if you count "type assertions"):

    1) Add access to properties through Interface methods

    type Post interface {
      GetMetadata() bool
      Title() string // Added Title method
    }
    
    func (ig *YouTubeVideo) Title() string {
      return ig.Title     
    }
    
    ...
    
    fmt.Println(thePost.Title())
    

    2) Access the properties with a type switch

    switch v := thePost.(type) {
    case *YouTubeVideo:
        fmt.Println(v.ChannelTitle)
    case *InstagramPic:
        fmt.Println(v.PublishedAt)
    }
    

    Alternative 1) is useful if all types that implements a Post also should give access to a certain property. 2) allows you to access fields specific for that type, but it requires then a case for each type.

    Setting a Post's field value

    Just like when getting, you can't directly set an Interface value's fields. In you case you should first set the desired fields before storing it in the interface:

    v := new(YouTubeVideo)
    v.ID = pid
    thePost = v // Store the *YouTubeVideo in thePost
    

    Or a bit shorter:

    thePost = &YouTubeVideo{ID: pid}
    

    Final note

    With some tuning, your structure should work using interfaces and type switches. But exactly how to best structure it is dependent on your specific situation which we have too little information about.

    To get a better understanding on how to use interfaces, I recommend reading: Effective Go: Interfaces and Types

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?