"".NoNamedReturnParams t=1 size=243 args=0x40 locals=0x0 0x0000 TEXT "".NoNamedReturnParams(SB), $0-64 0x0000 MOVQ $0, "".~r1+16(FP) 0x0009 LEAQ "".~r1+24(FP), DI 0x000e XORPS X0, X0 0x0011 ADDQ $-16, DI 0x0015 DUFFZERO $288 0x0028 MOVQ "".i+8(FP), AX 0x002d CMPQ AX, $1 0x0031 JEQ $0, 199 0x0037 CMPQ AX, $2 0x003b JEQ $0, 155 0x003d CMPQ AX, $3 0x0041 JNE 111 0x0043 MOVQ "".statictmp_2(SB), AX 0x004a MOVQ AX, "".~r1+16(FP) 0x004f LEAQ "".~r1+24(FP), DI 0x0054 LEAQ "".statictmp_2+8(SB), SI 0x005b DUFFCOPY $854 0x006e RET 0x006f MOVQ "".statictmp_3(SB), AX 0x0076 MOVQ AX, "".~r1+16(FP) 0x007b LEAQ "".~r1+24(FP), DI 0x0080 LEAQ "".statictmp_3+8(SB), SI 0x0087 DUFFCOPY $854 0x009a RET 0x009b MOVQ "".statictmp_1(SB), AX 0x00a2 MOVQ AX, "".~r1+16(FP) 0x00a7 LEAQ "".~r1+24(FP), DI 0x00ac LEAQ "".statictmp_1+8(SB), SI 0x00b3 DUFFCOPY $854 0x00c6 RET 0x00c7 MOVQ "".statictmp_0(SB), AX 0x00ce MOVQ AX, "".~r1+16(FP) 0x00d3 LEAQ "".~r1+24(FP), DI 0x00d8 LEAQ "".statictmp_0+8(SB), SI 0x00df DUFFCOPY $854 0x00f2 RET
All fine and dandy, but if that looks a bit repetitive to you, you are quite right. Essentially for each of the return statements the object to be returned is more or less allocated/initialized (or more precisely copied via the DUFFCOPYmacro).
It reduces the size of the function down from 243 to 67 bytes. Also as an additional benefit you will save some CPU cycles upon exiting out because there is no need anymore to do anything in order to setup the return value.
// parse credentialHeader string into its structured form. funcparseCredentialHeader(credElement string) (ch credentialHeader) { creds := strings.Split(strings.TrimSpace(credElement), "=") iflen(creds) != 2 { return } if creds[0] != "Credential" { return } credElements := strings.Split(strings.TrimSpace(creds[1]), "/") iflen(credElements) != 5 { return } iffalse/*!isAccessKeyValid(credElements[0])*/ { return } // Save access key id. cred := credentialHeader{ accessKey: credElements[0], } var e error cred.scope.date, e = time.Parse(yyyymmdd, credElements[1]) if e != nil { return } cred.scope.region = credElements[2] if credElements[3] != "s3" { return } cred.scope.service = credElements[3] if credElements[4] != "aws4_request" { return } cred.scope.request = credElements[4] return cred }
隐含的return value的方式
Note that actually the ch variable is a normal local variable just like any other local variable that is defined within the function. And as such you can change its value from the default ‘zero’ state (but of course then the modified version will be returned upon exiting out).
others uses of named return values
As pointed out by several persons, another benefit of named return values is the use in closures (i.e. defer statements). Thus one may access the named return value in a function that is called as the result of a defer statement and act accordingly.
conclusion
So we will be gradually adopting named return values more and more, both for new code as well as for existing code.
future to integration with gofmt to modify the source automatically