在Go中,未命名的参数是否有用? [英] Is unnamed arguments a thing in Go?

查看:119
本文介绍了在Go中,未命名的参数是否有用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用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中未修饰的函数参数的用途是什么?

解决方案

未命名的参数完全有效.规范中的参数声明:

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

如您所见,IdentifierList(一个或多个标识符名称)放在方括号中,这意味着它是可选.仅Type是必需的.

之所以这样做,是因为名称对于调用方法或函数的人来说并不重要.重要的是参数的类型及其顺序.在此答案中对此进行了详细说明:在Golang中获取方法参数名称

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

当您不命名时,是因为您不想引用它.

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

例如,因为参数在那儿" (已传递),但是您不需要它,也不想使用它.如果我不需要它,为什么会在那里?

因为某人或某物命令要求存在特定参数.例如,您要实现接口,或者要传递其签名由所需函数类型定义的函数值.

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

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

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

type DiscardWriter struct{}

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

仅此而已:我们不使用接收器,也不使用参数.两者都可以不命名.实现完全按照其应有的方式进行.

这样做(使用未命名的参数)还会记录该值未被使用/引用.

另一个原因可能是提供 forward 兼容性.如果发布了一个库,则在不破坏向后兼容性的情况下就不能更改或扩展参数列表(并且在Go中没有函数重载:如果您想要2个具有不同参数的变量,它们的名称也必须不同).因此,您可以及早声明带有其他参数的导出函数或方法,但是由于您尚未使用它们,因此可以不对其命名.此示例中的示例在以下答案中进行了详细说明:为什么Go允许编译未使用的函数参数?

这里要注意的一件事是,您不能混合使用已命名和未命名的参数.如果您命名,则必须全部命名.如果您不需要全部,则可以使用空白标识符,如下例所示:

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

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

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

另一个相关问题:

在Golang正常功能

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

在Golang中获取方法参数名称

I am writing a parser in Go for Go, and to test it I downloaded a bunch of files from github projects.
In https://github.com/andlabs/ui I bumped into a file containing this piece of code:

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

It confuse me a bit to see a pointer to a Button without a name as a function argument, which makes it impossible to reference from inside the function.
However, it seems to be syntactically correct given that the compiler doesn't complains.
What is the purpose of unamed functions arguments in Go?

解决方案

Unnamed parameters are perfectly valid. The Parameter declaration from the spec:

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

As you can see, the IdentifierList (the identifier name or names) is in square brackets, which means it's optional. Only the Type is required.

The reason for this is because the names are not really important for someone calling a method or a function. What matters is the types of the parameters and their order. This is detailed in this answer: Getting method parameter names in Golang

Generally you name variables and parameters so that you can refer to them.

When you don't name something, it's because you don't want to refer to it.

So the question should rather be: Why would I not want to refer to a parameter?

For example because the parameter "is there" (it is passed), but you don't need it, you don't want to use it. Why would it be there if I don't need it?

Because someone or something dictates for specific parameters to be there. For example you want to implement an interface, or you want to pass a function value whose signature is defined by the function type that is expected.

Let's see an example. We have the following MyWriter interface:

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

A simplified io.Writer which only returns an error, but does not report the number of bytes written. If you'd want to provide an implementation which just discards the data (similar to ioutil.Discard), then the implementation does not use (does not need to use) its argument:

type DiscardWriter struct{}

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

And that's all: we don't use the receiver, we don't use the argument. Both can be unnamed. And the implementation does exactly what it should.

Doing so (using unnamed parameters) also documents that the value is not used / referred to.

Another reason can be to provide forward compatibility. If you release a library, you can't change or extend the parameter list without breaking backward compatibility (and in Go there is no function overloading: if you want 2 variants with different parameters, their names must be different too). So you may declare an exported function or method with additional parameters early, but since you don't use them yet, you may leave them unnamed. An example of this is detailed in this answer: Why does Go allow compilation of unused function parameters?

One thing to note here is that you can't mix named and unnamed parameters. If you name some, you must name all. If you don't need all, you may use the blank identifier like in this example:

A simple web server which responds with the "Hello" text to all requests:

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

The handler function sending back the "Hello" text only uses the response writer w, but not the request structure, so the blank identifier is used as its name.

Another related question:

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

Also somewhat related, but regarding using / naming returned values:

Return map like 'ok' in Golang on normal functions

And regarding getting method / function parameter names:

Getting method parameter names in Golang

这篇关于在Go中,未命名的参数是否有用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆