Return map like 'ok' in Golang on normal functions

13,280

Solution 1

map is different because it is a built-in type and not a function. The 2 forms of accessing an element of a map is specified by the Go Language Specification: Index Expressions and backed by the compiler.

With functions you can't do this. If a function has 2 return values, you have to "expect" both of them or none at all.

However you are allowed to assign any of the return values to the Blank identifier:

s, b := Hello()    // Storing both of the return values

s2, _ := Hello()   // Storing only the first

_, b3 := Hello()   // Storing only the second

You can also choose not to store any of the return values:

Hello()            // Just executing it, but storing none of the return values

Note: you could also assign both of the return values to the blank identifier, although it has no use (other than validating that it has exactly 2 return values):

_, _ = Hello()     // Storing none of the return values; note the = instead of :=

You can also try these on the Go Playground.

Helper function

If you use it many times and you don't want to use the blank identifier, create a helper function which discards the 2nd return value:

func Hello2() string {
    s, _ := Hello()
    return s
}

And now you can do:

value := Hello2()
fmt.Println(value)

Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic First() function which discards the second (or any further) return values:

func First[T any](first T, _ ...any) T {
    return first
}

This is available in github.com/icza/gog, as gog.First() (disclosure: I'm the author).

Using it:

value := First(Hello())
fmt.Println(value)

Solution 2

In addition to the explanation of @icza:

  • I don't recommend using a helper function there. Especially if the Hello function is your own function.
  • However, if you can't control it, then it's fine to use a helper.
  • If it's your own function, it's better to change the signature of your function. Probably, you made a design mistake somewhere.

You can also do this:

package main

import "fmt"

func Hello() (string, bool) {
    return "hello", true
}

func main() {
    // Just move it one line above: don't use a short-if
    value, ok := Hello()
    if ok {
        fmt.Println(value)
    }
}
Share:
13,280

Related videos on Youtube

Michael Wasser
Author by

Michael Wasser

Currently creating products and exploring new opportunities for improvement within Healthcare and Education through the use of technology. Creator of HealthSherpa.com, Raveld, and Apptio CloudExpress.

Updated on April 20, 2022

Comments

  • Michael Wasser
    Michael Wasser about 2 years

    In Go, the following works (note one use of the map has one return, the other has two returns)

    package main
    
    import "fmt"
    
    var someMap = map[string]string { "some key": "hello" }
    
    func main() {
        if value, ok := someMap["some key"]; ok {
            fmt.Println(value)
        }
    
        value := someMap["some key"]
        fmt.Println(value)
    }
    

    However, I have no idea how to do this same thing with my own function. Is it possible to have similar behavior with an optional return like map?

    For example:

    package main
    
    import "fmt"
    
    func Hello() (string, bool) {
        return "hello", true
    }
    
    func main() {
        if value, ok := Hello(); ok {
            fmt.Println(value)
        }
    
        value := Hello()
        fmt.Println(value)
    }
    

    Wont compile (due to the error multiple-value Hello() in single-value context) ... is there a way to make this syntax work for the function Hello()?

  • Michael Wasser
    Michael Wasser over 9 years
    I had suspected as much, but wasn't sure as I had trouble googling for the docs / a definitive answer. Thanks for the reference to the docs as well!