Search code examples
gotype-assertion

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


Solution

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