Michal Škultéty
Michal Škultéty

Reputation: 228

Variable type of input parameter in function

I created a function that gets the last comment of a user on Pull Request. I am using "github.com/google/go-github/github" package. I would like to use it for []*github.IssueComment and []*github.PullRequestComment type. Is there a way for the type of the input parameter to be variable so I dont have to specify it in the function definition and function can be called using either of the type?

func getLastUserInteractionPR(comments_array *github.IssueComment OR *github.PullRequestComment)(*github.IssueComment OR *github.PullRequestComment) {
}

Using of generics:

func getLastUserInteractionPR(comments_array any)(any) {
}

is a emergency solution, since the whole project I am working on is written in Go 1.14 and this funcionality is available from GO 1.18

When I try to use empty interface{} as input type:

func getLastUserInteractionPRIssue(comments_array interface{})(*github.IssueComment) {

comments_array []*github.IssueComment(comments_array); err {
fmt.Println("success")
    } else {
        fmt.Println("failure")
    }
}

Upvotes: 1

Views: 54

Answers (1)

Sandy Cash
Sandy Cash

Reputation: 406

Do you care about the internal structure of e.g. an IssueComment?

type IssueComment struct {
    ID        *int64     `json:"id,omitempty"`
    NodeID    *string    `json:"node_id,omitempty"`
    Body      *string    `json:"body,omitempty"`
    User      *User      `json:"user,omitempty"`
    Reactions *Reactions `json:"reactions,omitempty"`
    CreatedAt *time.Time `json:"created_at,omitempty"`
    UpdatedAt *time.Time `json:"updated_at,omitempty"`
    // AuthorAssociation is the comment author's relationship to the issue's repository.
    // Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
    AuthorAssociation *string `json:"author_association,omitempty"`
    URL               *string `json:"url,omitempty"`
    HTMLURL           *string `json:"html_url,omitempty"`
    IssueURL          *string `json:"issue_url,omitempty"`
}

As in, do you care about extracting some specific field from that? PullRequestComment is a larger struct (it has more fields), do you care about extracting some field from that?

Or do you just want a string representation of each? What you do very much depends on what you want to do with the passed value(s).

If you just want a string representation of each, you could use the extreme (and, honestly, not very safe - I don't recommend this) example of having your function accept a slice of fmt.Stringer objects:

func DoStuffWithStringifiedComments(cs []fmt.Stringer) {
  // Both IssueComment and PullRequestComment provide String()
  // methods and therefore implement fmt.Stringer
  for _, comment := range cs {
    DoSomethingWith(comment.String())
  }
}

Your slice can now include objects of either type and nothing will blow up. Downside: it can also include a couple of bajillion other types, none of which you want. So you'd need to add a type assertion check:

switch t := comment.(type) {
  case github.IssueComment:
    // Do good stuff
  case github.PullRequestComment:
    // Do other good stuff
  default:
    // Yell and scream about the value of t
}

If there are fields you want to extract, you're going to have to combine a function taking something like []interface{} (make it a slice of empty interfaces, not an empty interface standing in for the slice), iterate over it and do a type check on each element of the slice, and pull out whatever fields are meaningful as long as the element is of a type you expect:

func DoStuff(comments []interface{}) error {
  for _, c : = range comments {
    if ic, ok := c.(*github.IssueComment); ok { // Remove the deref if your slice contains values, not references
      // Pull out fields and do IssueComment-specific things
      ProcessIssueComment(ic)
    } else if prc, ok := c.(*github.PullRequestComment); ok {
      // Do PRComment-specific things
      ProcessPullRequestComment(prc)
    } else {
      return(fmt.Errorf("I did not want something of type %s", t))
    }
  }
  return nil
}

Also: lobby the project owner (if that isn't you) to move to a current version of go. 1.14 only came out in 2020, but that's an eternity in go releases.

Upvotes: 1

Related Questions