Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why map and type assertion can return 1 or 2 values?

To define a map, we can do such a thing:

value, present := m["key"]

or:

value := m["key"]

and with type assertion, we can do:

var i interface{} = "hello"

s := i.(string)
fmt.Println(s)

s, ok := i.(string)
fmt.Println(s, ok)

but I can't find a way to define a func that can return 1 value or 2-values.

For instance:

func hello() (string, error) {
    return "world", nil
}

When I invoke this func I get:

v, ok := hello() // valid
v := hello() // invalid

PS: I know how something like template.Must works, but it seems different. I really want to know how Map and type assertion can do the magic, so I can apply it to functions.

Thanks in advance. (Am I clear? I have poor English sorry).

like image 628
Gimo Avatar asked Mar 27 '16 06:03

Gimo


2 Answers

The Go Programming Language Specification

Function types

A function type denotes the set of all functions with the same parameter and result types.

FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

Blank identifier

The blank identifier is represented by the underscore character _.

Assignments

The blank identifier provides a way to ignore right-hand side values in an assignment:

x, _ = f()  // evaluate f() but ignore second result value

Maps, type assertions, and the for statement with a range clause are special features of the Go programming language. You can't have a variable number of return values for an ordinary function type.

You can ignore a return value with an underscore (_), the blank identifier, or you can use a wrapper function. For example,

package main

import "fmt"

func two() (int, bool) {
    return 42, true
}

func one() int {
    r, _ := two()
    return r
}

func main() {
    r, ok := two()
    r, _ = two()
    r = one()
    fmt.Println(r, ok)
}
like image 117
peterSO Avatar answered Oct 30 '22 14:10

peterSO


Map and type assertions can do this because they are not functions, but structures of the language. The behavior is described in the spec

An index expression on a map a of type map[K]V used in an assignment or initialization of the special form

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]

yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.

and

A type assertion used in an assignment or initialization of the special form

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)

yields an additional untyped boolean value. The value of ok is true if the assertion holds. Otherwise it is false and the value of v is the zero value for type T. No run-time panic occurs in this case.

It is not something that can be done on general functions, hence the Must pattern that explicitely reproduce the same behavior.

like image 33
Elwinar Avatar answered Oct 30 '22 13:10

Elwinar