Go中的未命名参数是什么?

时间:2016-12-03 18:06:10

标签: go arguments

我正在Go for Go中编写一个解析器,为了测试它我从github项目中下载了一堆文件。
https://github.com/andlabs/ui中,我碰到了包含这段代码的文件:

func moveLabel(*Button) {
    from := movingCurrent
    to := 0
    if from == 0 {
        to = 1
    }
    movingBoxes[from].Delete(0)
    movingBoxes[to].Append(movingLabel, false)
    movingCurrent = to
}

让我感到困惑的是看到一个指向Button的指针而没有名称作为函数参数,这使得无法从函数内部引用。
但是,鉴于编译器没有抱怨,它似乎在语法上是正确的 Go中的已命名函数参数的用途是什么?

3 个答案:

答案 0 :(得分:19)

未命名的参数完全有效。规范中的Parameter declaration

ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

如您所见,IdentifierList(标识符名称或名称)位于方括号中,表示它是可选。只需要Type

之所以这样,是因为名称对于调用方法或函数的人来说并不重要。重要的是参数的类型及其顺序。这个答案详细说明:Getting method parameter names in Golang

通常,您可以命名变量和参数,以便引用它们。

如果你没有说出某些名字,那就是因为你不想引用它。

所以问题应该是:为什么我不想引用参数?

例如,因为参数"是" (已通过),但您不需要它,您不想使用它。如果我不需要它,为什么会在那里呢?

因为某人或某事指示特定参数。例如,您想要实现一个接口,或者您想要传递一个函数值,其签名由期望的函数类型定义。

让我们看一个例子。我们有以下MyWriter界面:

type MyWriter interface {
    Write(p []byte) error
}

简化的io.Writer,它只返回错误,但不报告写入的字节数。如果您想提供一个只丢弃数据的实现(类似于ioutil.Discard),那么实现不会使用(不需要使用)其参数:

type DiscardWriter struct{}

func (DiscardWriter) Write([]byte) error { return nil }

这就是全部:我们不使用接收器,我们不会使用这个参数。两者都可以是未命名的。并且实现完全符合它的要求。

这样做(使用未命名的参数)也文档表示没有使用/引用该值。

另一个原因可能是提供转发兼容性。如果您发布了库,则无法在不破坏向后兼容性的情况下更改或扩展参数列表(并且在Go中没有函数重载:如果您想要2个具有不同参数的变体,它们的名称也必须不同)。因此,您可以尽早声明带有其他参数的导出函数或方法,但由于您尚未使用它们,因此可能会将它们保留为未命名。此答案中详细介绍了此示例:Why does Go allow compilation of unused function parameters?

这里要注意的一点是,您无法混合命名和未命名的参数。如果你说出一些名字,你必须给所有人命名。如果您不需要所有内容,则可以使用此示例中的blank identifier

一个简单的Web服务器,它使用"Hello"文本响应所有请求:

http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
    io.WriteString(w, "Hello")
})
panic(http.ListenAndServe(":8080", nil))

发送回"Hello"文本的处理函数仅使用响应编写器w,而不使用请求结构,因此空白标识符用作其名称。

另一个相关问题:

Why must we declare a variable name when adding a method to a struct in Golang?

也有些相关,但关于使用/命名返回值:

Return map like 'ok' in Golang on normal functions

关于获取方法/函数参数名称:

Getting method parameter names in Golang

答案 1 :(得分:2)

未命名的参数有效但不可引用。

它们只是为了满足接口和签名。

答案 2 :(得分:0)

未命名函数参数的目的是用于在函数代码中未引用的参数(它们是函数的局部变量),因此不需要名称。关于匿名变量的一个有趣的注解是,它们实际使用的频率比您想象的还要普遍。在Go中,函数的返回值通常被列为类型,但实际上它们也是函数的局部变量,可以对其进行命名和操作。

请参阅golang.org上“有效的Go”页面中的示例 https://golang.org/doc/effective_go.html#named-results

func ReadFull(r Reader, buf []byte) (n int, err error) {
    for len(buf) > 0 && err == nil {
        var nr int
        nr, err = r.Read(buf)
        n += nr
        buf = buf[nr:]
    }
    return
}