Question

How can I pass dictionary as list of arguments for function like in Python 3 in Go?

Python 3:

def bar(a,b,c):
    print(a,b,c)

args={c: 1, b: 2, a: 3}
bar(**args)

Go blank:

func bar( a, b, c int) {
    fmt.Printf("%d, %d, %d", a, b, c)
}

func main(){
    args := make(map[string]int)
    args["a"] = 3
    args["b"] = 2
    args["c"] = 1
    // what next ?
}
Était-ce utile?

La solution

I don't believe this is possible. You'd need to use a struct to do anything even remotely close to this (and it is a remote likeness)

type Args struct {
    A, B, C int
}

func bar(args *Args) {
    fmt.Printf("%d, %d, %d", args.A, args.B, args.C)
}

func main() {
    args := new(Args)
    args.A = 3
    args.B = 2
    args.C = 1
    bar(args)
}

Autres conseils

In addition to the other answers, which I see no need to repeat, be aware that Go will auto-unpack function calls with multiple return arguments provided:

  1. Every return value is a parameter of the function
  2. Every parameter is a return value of the function

(That is, the types of the function's argument list is identical to the other function's return list).

func Args() (a int, b int, c int) {
    return 1,2,3
}

func Bar(a,b,c int) {
    fmt.Println(a,b,c)
}

func main() {
    Bar(Args())
}

Will print 1,2,3. Obviously this example is a tad silly, but I find this covers most cases of tuple and dict unpacking as arguments in Python, which tend to be a quick and dirty way of passing one function's return values as another function's arguments.

For completeness sake you can either use what dskinner said, or if you want a "dictionary" (called map in Go) you could use one easily, for example :

package main

import "log"

type ArgsMap map[string]interface{}

func bar(am ArgsMap) {
    if v, ok := am["foo"].(string); ok {
        log.Println("bar", v)
    } else {
        log.Println("bar no foo")
    }
}

// Or

type Args struct {
    foo     string
    boo     int
    a, b, c float32
}

func bar2(a Args) {
    if a.foo != "" {
        log.Println("bar2", a.foo)
    } else {
        log.Println("bar2 no foo")
    }
}

func main() {
    bar(ArgsMap{"foo": "map", "blah": 10})
    bar(ArgsMap{})

    bar2(Args{foo: "struct"})
    bar2(Args{})
}

There is no direct equivalent to Python's *args/**kwargs syntax. You need to use one of the solutions outlined in the other answers.

In case you just need to pass an unknown number of arguments you can make your function variadic.

package main

import (
    "fmt"
)

func bar(numbers ...int) {
    fmt.Printf("%d\n", numbers)
}

func main() {
    bar(3, 2, 1)       // prints [3 2 1]
    bar(5, 4, 3, 2, 1) // prints [5 4 3 2 1]
}

Play

This is not thoroughly tested for a wide range of values, but it works for a few simple cases. Feel free to expand it further for your own needs. It's also not guaranteed to be anything like the best way to do this, and error checking is left as an exercise for the reader.

func parseArguments(args ...interface{}) map[string]interface{} {
    if args == nil {
        return nil
    }
    if x,ok := args[0].(map[string]interface{}); ok {
        return x
    }
    x := map[string]interface{}{}
    for i := 0; i < len(args); i += 2 {
        x[ args[i].(string) ] = args[i+1]
    }
    return x
}

func DoSomethingCool(x ...interface{}) {
    args := parseArguments(x);
    // args is now a map of type map[string]interface{}
}

You can now call DoSomethingCool() in any of the following ways:

// No arguments
DoSomethingCool()

// These two are equivalent, and result in
// args = map[string]interface{}{
//     "foo": "bar",
//     "baz": "qux",
//  } 
DoSomethingCool(map[string]string{"foo": "bar", "baz": "qux"})
DoSomethingCool("foo","bar","baz","qux")

// Or you can even mix types for the keys, thanks to interface{}
// These two are also equivalents and result in
// args = map[string]interface{}{
//     "foo": 20,
//     "bar": false,
//  } 

DoSomethingCool(map[string]interface{}{"foo": 20, "bar": false})
DoSomethingCool("foo",20,"bar",false)

If you don't have a need to mix value types, you could just as well use map[string]string I imagine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top