未命名参数在 Go 中是一回事吗? [英] Is unnamed arguments a thing in Go?

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

问题描述

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

func moveLabel(*Button) {从 := 移动电流到:= 0如果从 == 0 {到 = 1}movingBoxes[from].Delete(0)movingBoxes[to].Append(movingLabel, false)移动电流 = 到}

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

解决方案

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

ParameterDecl = [ IdentifierList ] [ "..." ] 类型.

如您所见,IdentifierList(标识符名称或名称)在方括号中,这意味着它是可选.只需要Type.

这是因为名称对于调用方法或函数的人来说并不重要.重要的是参数的类型及其顺序.这在这个答案中有详细说明:在 Golang 中获取方法参数名称

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

当你不为某事命名时,那是因为你不想提及它.

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

比如因为参数"is there"(它被传递了),但是你不需要它,你不想使用它.如果我不需要它为什么会在那里?

因为某人或某物规定特定参数存在.例如你想实现一个接口,或者你想传递一个函数值,它的签名是由预期的函数类型定义的.

让我们看一个例子.我们有以下 MyWriter 接口:

type MyWriter interface {写(p []字节)错误}

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

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

仅此而已:我们不使用接收器,也不使用参数.两者都可以无名.并且实现正是它应该做的.

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

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

这里要注意的一点是,您不能混合命名参数和未命名参数.如果你命名一些,你必须命名所有.如果您不需要全部,您可以使用 空白标识符,如本例所示:>

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

http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {io.WriteString(w, "你好")})恐慌(http.ListenAndServe(:8080",零))

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

另一个相关问题:

为什么在Golang中向结构体添加方法时必须声明变量名?

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

返回地图中的ok"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天全站免登陆