【问题标题】:Golang pass nil as optional argument to a function?Golang将nil作为可选参数传递给函数?
【发布时间】:2015-09-14 15:54:53
【问题描述】:

在 Golang 中,http.NewRequest 有这样的规范:

func NewRequest(method, urlStr string, body io.Reader) (*Request, error)

但是,如果我不想将body 传递给io.Reader 对象,我可以将nil 作为body 选项传递,如下所示:

req, err := http.NewRequest("GET", "http://www.blahblah.org", nil)

如何在我的代码中实现此功能?我有一个函数,我想传递一个可选的字符串值,以便它可以通过 API 结果进行分页,但是如果我将 nil 传递给字符串输入,我会得到:

./sn-ps.go:32: 无法将 nil 转换为字符串类型

我的函数的参数如下所示:

func getChallenges(after string) ([]challenge, string, error)

【问题讨论】:

    标签: go


    【解决方案1】:

    Go 没有“可选”参数作为其他语言中普遍理解的概念; nil 只是接口的零值(在本例中为io.Reader)。

    一个字符串的等效零值是一个空字符串:

    getChallenges("")
    

    如果要接受 0 个或多个相同的参数类型,请使用可变参数语法:

    func getChallenges(after ...string) ([]challenge, string, error)
    

    【讨论】:

    • 空字符串 "" 是我使用的,不过我将实现可变参数语法。我认为这类似于 python 中的 *arg/**kwargs 。干杯!
    【解决方案2】:

    你可以修改你的函数来接收指针值,像这样:

    func getChallenges(after *string) ([]challenge, string, error)

    然后您可以将nil 作为参数传递给它。但是不要忘记在取消引用之前检查after 函数中的nil 值,否则你会得到一个空指针异常:

    func getChallenges(after *string) ([]challenge, string, error) {
        if after == nil {
            // No value specified
        } else {
            fmt.Printf("After: %s\n", *after) // Note pointer dereferencing with "*"
        }
        // ...
    }
    

    另一种选择:

    只需使用两个函数:

    func getChallenges(after string) {}
    
    func getAllChallenges() {
        return getChallenges(/* some default value here */)
    }
    

    【讨论】:

    • 将参数设为 *string 的一个巨大缺点是您不能获取字符串文字的地址,也不会自动为您打包字符串。 play.golang.org/p/d4jvq5xrAk
    • "just add another function" 参数可能导致处理多个排列所需的方法激增,需要为这些方法,并增加了学习使用更多方法而不是更少方法的包的负担。 #jmtcw
    【解决方案3】:

    您可以使用椭圆运算符发送可选参数。不要在可选参数中传递任何内容并检查参数的长度。 它应该可以解决您的问题

    func foo(params ...int) {
       fmt.Println(len(params))
    }
    
    func main() {
        foo()
        foo(1)
        foo(1,2,3)
    }
    

    【讨论】:

      【解决方案4】:

      也许用struct 包装它?

      type NilableString struct {
          value string;
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用反射。 其实io.Reader是一个接口。

        所以你可以定义像func getChallenges(after interface{}) ([]challenge, string, error)这样的签名

        interface{} 是一个空接口,即任何东西的接口。

        但我建议你使用语法 args... 来传递 slice ,请参考 fmt.Printf 实现的用法,因为如果你不传递任何字符串,则 slice len 为 0 并且 这将避免我认为对您的功能来说太重的反射。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-27
          • 1970-01-01
          • 1970-01-01
          • 2021-04-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多