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

And*_*ume 4 go

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

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

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

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

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

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

Kae*_*dys 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)   
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,更常见的样式是您的响应本身具有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()
}
Run Code Online (Sandbox Code Playgroud)

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