在Golang中返回输入变量

I just got started with Golang, and I saw the typical swap function example:

func swap(x, y string) (string, string) {
    return y, x
}

I automatically thought that the named returns could have solved it and that it was a sweeter example, so I tried the shorter version:

package main

import "fmt"

func swap(z, y int) (z, y int) {
    return
}

func main() {
    fmt.Println(swap(2, 3))
}

But to by my surprise it didn't compile complaining about a duplicate argument. Why is not possible to return an input argument? Am I doing something wrong or it is just not supported?

I thought this was a totally valid use case and that it could have been many other examples for this usage.

I guess problem is not in returning input argument, but in names duplication: y and z are declared twice on the same level and compiler cannot distinguish.

I'm also a Golang beginner. Here's what I managed to find out.

The problem is essentially, that you declare two variables named z, then expect them to be unified. This is not supported, and in fact would go against the main goal of named return types, which is to document the meaning of the values returned.

To explain in more detail, this is a bit like writing the following code:

func badFunction(a int) int {
    var a int = 0
    return a
}

A variable is declared twice, and this is confusing for Go. If we look at what the 'tour of go' has to say about named return values, we can see the issue. It's not the greatest source, but it's a source nonetheless:

Go's return values may be named. If so, they are treated as variables defined at the top of the function.

That is to say, your example is almost exactly like badFunction. To the compiler, it looks a bit like this:

func swap(a, b int) (int, int) {
    var a int = 0
    var b int = 0
    return b, a
}

Naturally, the compiler complains about a redeclared in block, which is a related though admittedly not equal error. The error message you receive there appears to essentially be a pre-check to prevent the user from seeing the code produced when desugared.


As this Stackoverflow question reports, named return values should essentially be for documentation only. However, it does mention the possibility of accidental shadowing. It may be that an earlier Go version supported this, but has since been changed to prevent bugs due to this kind of name collision, however I have not found anything pertaining to this.

The effective go section on the topic also has something to say:

The return or result "parameters" of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.

The names are not mandatory but they can make code shorter and clearer: they're documentation.


TL;DR: The compiler doesn't unify names in the way you might expect. This kind of implicit shadowing not supported, and should be actively avoided to prevent certain easily avoidable bugs.