在Go中传递具有未知参数类型的函数引用

时间:2017-10-20 15:52:32

标签: go

我正在使用具有两个函数的第三方库,每个函数都返回不同的类型。例如。 ArticleResponseCommentResponse

我想将调用其中任何一个函数的结果传递给我自己的函数。作为该函数的第二个参数,我想传递一个函数引用,该函数引用描述如何将该响应打印到stdout。

response := GetArticles()
processResponse(response, printResponse)

func printResponse(response <what_type?>) {
    for i := range response.Articles {
        fmt.Println(response.Articles[i].Title)
    }
}

我不清楚如何强制或创建泛型类型,以便printResponse函数知道期望在其参数中传递什么。

如果我没有提供足够好的描述我在这里尝试做什么,请告诉我,我会编辑/更新问题。

2 个答案:

答案 0 :(得分:7)

在这种情况下,您唯一真正的选择是processResponse接受interface{}和接受相同的函数,然后printResponse接受相同的空接口并键入 - 断言(或使用类型开关)。例如:

func main() {
    response := GetArticles()
    processResponse(response, printResponse)
}

func processResponse(response interface{}, printResponse func(interface{})) 
{
    // Process
    printResponse(response)
}

func printResponse(response interface{}) {
    switch r = reponse.(type) {
    case ArticleResponse:
        for i := range r.Articles {
            fmt.Println(r.Articles[i].Title)
        }
    case CommentResponse:
        for i := range r.Comments {
            fmt.Println(r.Comments[i].Topic, r.Comments[i].User)   
        }
    }
}

但是,更常见的样式是您的响应本身具有Print方法(或类似),并且您的流程函数接受表示该常用方法的接口。例如:

type ArticleReponse struct {
    // ...
}

func (a ArticleReponse) Print() {
    for i := range a.Articles {
        fmt.Println(a.Articles[i].Title)
    }
}

type CommentResponse struct {
    // ...
}

func (c CommentResponse) Print() {
    for i := range c.Comments {
        fmt.Println(c.Comments[i].Topic, c.Comment[i].User)
    }
}

type Response interface {
    Print()
}

func main() {
    response := GetArticles()
    processResponse(response)
}

func processResponse(response Response) 
{
    // Process
    response.Print()
}

此样式允许响应类型本身定义其打印行为,而processResponse函数仅知道它具有某种能够自行打印的类型。这也允许您将其他方法添加到processResponse(或其他任何)可能需要的响应接口,以便与这些类型进行交互,而无需实际知道它被赋予了哪种类型。这使得您的代码基本上不那么脆弱,因为它不再依赖于每种响应类型的实际实现细节。它还允许您通过模拟processReponse接口来单独测试Response

答案 1 :(得分:0)

您可以创建Content&amp; ContentList接口

type Content interface {
    GetTitle() string    
}

type ContentList interface {
    Contents() []Content 
}


func printResponse(response ContentList) {
    for content := range response.Contents() {
        fmt.Println(content.GetTitle())
    }
}

然后ArticleResponse&amp; CommentResponse应实施ContentList界面和Aticle&amp; Comment应该实现Content接口。