Gimo
Gimo

Reputation: 178

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).

Upvotes: 14

Views: 3435

Answers (2)

peterSO
peterSO

Reputation: 166765

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)
}

Upvotes: 8

Elwinar
Elwinar

Reputation: 9519

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.

Upvotes: 7

Related Questions