Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang alternative to c++ function with default params: multiple functions, or struct param

I would like to know the best practice in Go equivalent to C++ functions binding with default params, which may be easiest for the user to see the function params(with linter help).
What do you think will be the most GO style and easiest way to use the test function ?

An example function in C++:

void test(int x, int y=0, color=Color());

Equivalence in Go

1. With multiple signatures:

func test(x int)
func testWithY(x int, y int)
func testWithColor(x int, color Color)
func testWithYColor(x int, y int, color Color)

pro:

  • The linter will show all the possibilities for test
  • The compiler will take the shortest path

cons:

  • Can be overwhelmed when there is a lots of params

2. With struct parameter:

type testOptions struct {
    X      int
    Y      int
    color  Color
}

func test(opt *testOptions)

// user 
test(&testOptions{x: 5})

pro:

  • Only one signature
  • Can specify only some values

cons:

  • Need to define a struct
  • The values will be set by default by the system

With the help of the module github.com/creasty/defaults, there is a way to set default values (but with the cost of calling reflect in runtime).

type testOptions struct {
    X      int
    Y      int `default:"10"`
    color  Color `default:"{}"`
}

func test(opt *testOptions) *hg.Node {
    if err := defaults.Set(opt); err != nil {
        panic(err)
    }
}

pro:

  • set default values

cons:

  • Use of reflect in runtime

P.S.: I saw the use of variadic parameters ... or/with interface{} but I find it not easy to know which params to use (or maybe there is a way to indicate a params list to the linter).

like image 873
Scorpheus S Avatar asked Dec 18 '25 16:12

Scorpheus S


1 Answers

Either way will work fine, but in Go the functional options pattern might be more idiomatic for implementing such functionality.

It is based on the idea of accepting a variable amount of WithXXX type of functional arguments that extend of modify the behavior of the call.

type Test struct {
    X     int
    Y     int
    color Color
}

type TestOption func(*Test)

func test(x int, opts ...TestOption) {
    p := &Test{
        X: x,
        Y: 12,
        Color: defaultColor,
    }
    for _, opt := range opts {
        opt(p)
    }
    p.runTest()
}

func main() {
    test(12)
    test(12, WithY(34))
    test(12, WithY(34), WithColor(Color{1, 2, 3}))
}

func WithY(y int) TestOption {
    return func(p *Test) {
        p.Y = y
    }
}

func WithColor(c Color) TestOption {
    return func(p *Test) {
        p.color = c
    }
}
like image 155
rustyx Avatar answered Dec 21 '25 05:12

rustyx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!