Is it possible to work similar way like the function overloading or optional parameter in C# using Golang? Or maybe an alternative way?
The idiomatic answer to optional parameters in Go is wrapper functions:
func do(a, b, c int) {
// ...
}
func doSimply(a, b) {
do(a, b, 42)
}
Function overloading was intentionally left out, because it makes code hard(er) to read.
Neither function overloading nor optional arguments are directly supported. You could work around them building your own arguments struct. I mean like this (untested, may not work...) EDIT: now tested...
package main
import "fmt"
func main() {
args:=NewMyArgs("a","b") // filename is by default "c"
args.SetFileName("k")
ret := Compresser(args)
fmt.Println(ret)
}
func Compresser(args *MyArgs) string {
return args.dstFilePath + args.srcFilePath + args.fileName
}
// a struct with your arguments
type MyArgs struct
{
dstFilePath, srcFilePath, fileName string
}
// a "constructor" func that gives default values to args
func NewMyArgs(dstFilePath string, srcFilePath string) *MyArgs {
return &MyArgs{
dstFilePath: dstFilePath,
srcFilePath:srcFilePath,
fileName :"c"}
}
func (a *MyArgs) SetFileName(value string){
a.fileName=value;
}
There are some hints here using variadic arguments, for example:
sm1 := Sum(1, 2, 3, 4) // = 1 + 2 + 3 + 4 = 10
sm2 := Sum(1, 2) // = 1 + 2 = 3
sm3 := Sum(7, 1, -2, 0, 18) // = 7 + 1 + -2 + 0 + 18 = 24
sm4 := Sum() // = 0
func Sum(numbers ...int) int {
n := 0
for _,number := range numbers {
n += number
}
return n
}
Or ...interface{} for any types:
Ul("apple", 7.2, "BANANA", 5, "cHeRy")
func Ul(things ...interface{}) {
fmt.Println("<ul>")
for _,it := range things {
fmt.Printf(" <li>%v</li>\n", it)
}
fmt.Println("</ul>")
}
An approach I use sometime for constructing an object using New methods having different arguments is to have a "flavor" pseudo type. You can try it on the Go Playground https://play.golang.org/p/5To5AcY-MRe
package main
import "fmt"
type flavorA struct{}
type flavorB struct{}
var FlavorA = flavorA{}
var FlavorB = flavorB{}
type Something struct {
i int
f float64
}
func (flavor flavorA) NewSomething(i int) *Something {
return &Something{i:i, f:0.0}
}
func (flavor flavorB) NewSomething(f float64) *Something {
return &Something{i:0, f:f}
}
func main() {
fmt.Println(FlavorA.NewSomething(1), FlavorB.NewSomething(2))
}
When you have many arguments it may make sense to use a new struct for them or to define a new MyOptionBuilder type to build and store all the arguments and to construct nice defaults.
Here's a simple example where the go defaults for types are okay.
package main
import "fmt"
type FancyFuncOptions struct {
I int64
S string
F float64
//...many more...
}
func FancyFunc(opts *FancyFuncOptions) {
fmt.Println("%v", opts)
}
func main() {
// simple way
options := &FancyFuncOptions{S: "happy"}
FancyFunc(options)
In golang you'll see people using method-chaining for this, if the options have complex logic.
package main
import "fmt"
type FancyFuncOptions struct {
I int64
S string
F float64
//...many more...
}
// chaining style
func NewFancyFuncOptions() *FancyFuncOptions {
return &FancyFuncOptions{I: 100, S: "empty", F: 0.1}
}
func (o *FancyFuncOptions) SetI(i int64) *FancyFuncOptions {
o.I = i
return o
}
func (o *FancyFuncOptions) SetS(s string) *FancyFuncOptions {
o.S = s
return o
}
func FancyFunc(opts *FancyFuncOptions) {
fmt.Println("%v", opts)
}
func main() {
// fancier
options = NewFancyFuncOptions().SetI(234).SetS("happy")
FancyFunc(options)
(https://go.dev/play/p/Ae_6Y6kZa97)
Make sense?
Related
Below code is Map implementation using array, slice & pointers:
package gomap
import "fmt"
type Entry struct {
stockName string
stockValue float64
}
type bucket []Entry
type Map [4]bucket
type bucketElementPosition [4]int
var emptyPosition = bucketElementPosition{0, 0, 0, 0}
func Newmap() Map {
return Map{} // [(nil,0,0), (nil,0,0), (nil,0,0), (nil,0,0)]
}
func (m *Map) Lookup(key string) float64 {
bucketNumber := (key[0] - 'A') / 7
for _, entry := range m[bucketNumber] { // (*m)[bucketNumber]
if entry.stockName == key {
return entry.stockValue
}
}
return 0
}
func (m *Map) Insert(key string, value float64) {
bucketNumber := (key[0] - 'A') / 7
if cap(m[bucketNumber]) == 0 { // (*m)[bucketNumber]
fmt.Println("bucket number:", bucketNumber)
m[bucketNumber] = make([]Entry, 0, 100)
}
m[bucketNumber] = append(m[bucketNumber], Entry{key, value})
emptyPosition[bucketNumber]++
}
package main
import (
"fmt"
"github.com/myhub/cs61a/gomap"
)
func main() {
var stockData = gomap.Newmap()
(&stockData).Insert("AAPL", 94.56)
(&stockData).Insert("HSCO", 26.72)
(&stockData).Insert("NMZN", 697.45)
(&stockData).Insert("ZSFT", 50.81)
(&stockData).Insert("PMGN", 150.83)
fmt.Println((&stockData).Lookup("AAPL"))
fmt.Println((&stockData).Lookup("HSCO"))
fmt.Println((&stockData).Lookup("NMZN"))
fmt.Println((&stockData).Lookup("ZSFT"))
fmt.Println((&stockData).Lookup("PMGN"))
}
Code smell bucketNumber := (key[0] - 'A') / 7 can be taken care by reading bits and hash.
but for line type bucket []Entry
How to make the concrete type Map, Entry type agnostic? because key is fixed as string and value is fixed as float64
I completed the home assignment like this:
package gomap
import "fmt"
type Entry struct {
key, value interface{}
}
type Map struct {
buckets [4][]Entry
}
func Newmap() *Map {
return &Map{}
}
func (m *Map) bucketNumber(key interface{}) int {
s := fmt.Sprint(key)
return int(s[0]) % len(m.buckets)
}
func (m *Map) Lookup(key interface{}) interface{} {
bucketNumber := m.bucketNumber(key)
for _, entry := range m.buckets[bucketNumber] {
if entry.key == key {
return entry.value
}
}
return nil
}
func (m *Map) Insert(key interface{}, value interface{}) {
bucketNumber := m.bucketNumber(key)
m.buckets[bucketNumber] = append(m.buckets[bucketNumber], Entry{key, value})
}
https://play.golang.org/p/KmVSeDavc3y
There are a few ways you can do that. The most obvious is to use interface{} for key and value. However, there's a type-safe way of doing the keys. You can make Key an interface:
type Key interface {
// Returns the bucket number for the key
BucketNumber() int
// Eq compares the key with the given key
Eq(Key) bool
}
Then you can have an Entry using this key:
type Entry struct {
k Key
v interface{}
}
You can rewrite the map functions to use this key. Value would have to be an interface, and you have to use type assertions to get the underlying value.
Suppose I have a dependency that looks like this:
type Dependency interface {
Retrieve(transform func(row *Row) string) []string
}
And I'm using it in code that I'd like to unit test
// ...
result := dep.Retrieve(func(row *Row) string {
// ... do stuff
})
// ...
This is a contrived example, but consider it for something like gcloud pubsub, which has a Receive method that calls a user-defined function for each message it pulls.
If I use mockgen to get a mock of Dependency, how do I tell the mock how to behave? I'd want it to call its input function some number of times with some sets of input.
Here is some code while trying to understand what you wanted to achieve.
I don't use mockgen, but manually, you can do what you want. I totally changed the behavior between the original and the mocked call. Does it answer your questions?
package main
import (
"fmt"
)
var str = [...]string{
"world",
"night",
}
type Dependency interface {
Get(val string) string
}
type dependency struct {
i int
}
func (d *dependency) Get(fn func(int) string) string {
d.i++
d.i = d.i % len(str)
return "hello " + fn(d.i)
}
func main() {
d := dependency{}
myfn := func(idx int) string { return str[idx] }
fmt.Println(d.Get(myfn))
fmt.Println(d.Get(myfn))
fmt.Println(d.Get(myfn))
m := mock{}
fmt.Println(m.Get(myfn))
}
type mock struct {
}
func (m *mock) Get(fn func(int) string) string {
i := 0
j := (i + 1) % len(str)
k := (j + 1) % len(str)
return "mocked " + fn(i) + fn(j) + fn(k)
}
The play link:
https://play.golang.org/p/bb7WrmlIEN
Is there anyway to make a map of function pointers, but functions that take recievers? I know how to do it with regular functions:
package main
func someFunc(x int) int {
return x
}
func main() {
m := make(map[string]func(int)int, 0)
m["1"] = someFunc
print(m["1"](56))
}
But can you do that with functions that take recievers? Something like this (though I've tried this and it doesn't work):
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string](someStruct)func()int, 0)
s := someStruct{56}
m["1"] = someFunc
print(s.m["1"]())
}
An obvious work around is to just pass the struct as a parameter, but that's a little dirtier than I would have liked
You can do that using Method Expressions:
https://golang.org/ref/spec#Method_expressions
The call is a bit different, since the method expression takes the receiver as the first argument.
Here's your example modified:
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string]func(someStruct)int, 0)
s := someStruct{56}
m["1"] = (someStruct).someFunc
print(m["1"](s))
}
And here's a Go playground for you to test it:
https://play.golang.org/p/PLi5A9of-U
I try to write a function which takes any other function and wraps a new function around it. This is what I have tried so far:
package main
import (
"fmt"
)
func protect (unprotected func (...interface{})) (func (...interface{})) {
return func (args ...interface{}) {
fmt.Println ("protected");
unprotected (args...);
};
}
func main () {
a := func () {
fmt.Println ("unprotected");
};
b := protect (a);
b ();
}
When I compile this I get the error:
cannot use a (type func()) as type func(...interface { }) in function argument
Why is a function without arguments not compatible to a function with a variable number of arguments? What can I do to make them compatible?
Update:
The protected function should be compatible with the original:
func take_func_int_int (f func (x int) (y int)) (int) {
return f (1)
}
func main () {
a := func (x int) (y int) {
return 2 * x
}
b := protect (a)
take_func_int_int (a)
take_func_int_int (b)
}
Types are pretty concrete in Go. You could try
a := func(_ ...interface{}) {
fmt.Println("unprotected")
}
func (...interface{}) does not mean "any function that takes any number of any kind of arguments", it means "only a function which takes a variable number of interface{} arguments"
Alternatively rather than func(...interface{}) you can just use interface{} and the reflect package. See http://github.com/hoisie/web.go for an example.
EDIT: Specifically, this:
package main
import (
"fmt"
"reflect"
)
func protect(oldfunc interface{}) (func (...interface{})) {
if reflect.TypeOf(oldfunc).Kind() != reflect.Func {
panic("protected item is not a function")
}
return func (args ...interface{}) {
fmt.Println("Protected")
vargs := make([]reflect.Value, len(args))
for n, v := range args {
vargs[n] = reflect.ValueOf(v)
}
reflect.ValueOf(oldfunc).Call(vargs)
}
}
func main() {
a := func() {
fmt.Println("unprotected")
}
b := func(s string) {
fmt.Println(s)
}
c := protect(a)
d := protect(b)
c()
d("hello")
}
Ouput is
Protected
unprotected
Protected
hello
EDIT: To answer the update
Like I said above, types are pretty concrete in Go. The protect function returns a type func(...interface{}) which will never be assignable to func(int)int. I think you're probably either over-engineering your problem or misunderstanding it. However, here's a highly discouraged code snippet that would make it work.
First change protect to also return values:
func protect(oldfunc interface{}) (func (...interface{}) []interface{}) {
if reflect.TypeOf(oldfunc).Kind() != reflect.Func {
panic("protected item is not a function")
}
return func (args ...interface{}) []interface{} {
fmt.Println("Protected")
vargs := make([]reflect.Value, len(args))
for n, v := range args {
vargs[n] = reflect.ValueOf(v)
}
ret_vals := reflect.ValueOf(oldfunc).Call(vargs)
to_return := make([]interface{}, len(ret_vals))
for n, v := range ret_vals {
to_return[n] = v.Interface()
}
return to_return
}
}
Then make a convert function:
func convert(f func(...interface{}) (func(int) int) {
return func(x int) int {
r := f(x)
return r[0].(int)
}
}
Then your call would look like
take_func_int_int(convert(b))
But I promise this isn't what you actually want to do.
Step back and try to rework the problem. I've completely killed type-safety in these examples. What are you trying to accomplish?
package main
import "fmt"
// Here's a function that will take an arbitrary number
// of `int`s as arguments.
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
// Variadic functions can be called in the usual way
// with individual arguments.
sum(1, 2)
sum(1, 2, 3)
// If you already have multiple args in a slice,
// apply them to a variadic function using
// `func(slice...)` like this.
nums := []int{1, 2, 3, 4}
sum(nums...)
}
I come from JavaScript which has first class function support. For example you can:
pass a function as a parameter to another function
return a function from a function.
Can someone give me an example of how I would do this in Go?
Go Language and Functional Programming might help. From this blog post:
package main
import fmt "fmt"
type Stringy func() string
func foo() string{
return "Stringy function"
}
func takesAFunction(foo Stringy){
fmt.Printf("takesAFunction: %v\n", foo())
}
func returnsAFunction()Stringy{
return func()string{
fmt.Printf("Inner stringy function\n");
return "bar" // have to return a string to be stringy
}
}
func main(){
takesAFunction(foo);
var f Stringy = returnsAFunction();
f();
var baz Stringy = func()string{
return "anonymous stringy\n"
};
fmt.Printf(baz());
}
Author is the blog owner: Dethe Elza (not me)
package main
import (
"fmt"
)
type Lx func(int) int
func cmb(f, g Lx) Lx {
return func(x int) int {
return g(f(x))
}
}
func inc(x int) int {
return x + 1
}
func sum(x int) int {
result := 0
for i := 0; i < x; i++ {
result += i
}
return result
}
func main() {
n := 666
fmt.Println(cmb(inc, sum)(n))
fmt.Println(n * (n + 1) / 2)
}
output:
222111
222111
The related section from the specification: Function types.
All other answers here first declare a new type, which is good (practice) and makes your code easier to read, but know that this is not a requirement.
You can work with function values without declaring a new type for them, as seen in the below example.
Declaring a variable of function type which has 2 parameters of type float64 and has one return value of type float64 looks like this:
// Create a var of the mentioned function type:
var f func(float64, float64) float64
Let's write a function which returns an adder function. This adder function should take 2 parameters of type float64 and should returns the sum of those 2 numbers when called:
func CreateAdder() func(float64, float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
Let's write a function which has 3 parameters, first 2 being of type float64, and the 3rd being a function value, a function that takes 2 input parameters of type float64 and produces a value of float64 type. And the function we're writing will call the function value that is passed to it as parameter, and using the first 2 float64 values as arguments for the function value, and returns the result that the passed function value returns:
func Execute(a, b float64, op func(float64, float64) float64) float64 {
return op(a, b)
}
Let's see our previous examples in action:
var adder func(float64, float64) float64 = CreateAdder()
result := Execute(1.5, 2.5, adder)
fmt.Println(result) // Prints 4
Note that of course you can use the Short variable declaration when creating adder:
adder := CreateAdder() // adder is of type: func(float64, float64) float64
Try these examples on the Go Playground.
Using an existing function
Of course if you already have a function declared in a package with the same function type, you can use that too.
For example the math.Mod() has the same function type:
func Mod(x, y float64) float64
So you can pass this value to our Execute() function:
fmt.Println(Execute(12, 10, math.Mod)) // Prints 2
Prints 2 because 12 mod 10 = 2. Note that the name of an existing function acts as a function value.
Try it on the Go Playground.
Note:
Note that the parameter names are not part of the type, the type of 2 functions having the same parameter and result types is identical regardless of the names of the parameters. But know that within a list of parameters or results, the names must either all be present or all be absent.
So for example you can also write:
func CreateAdder() func(P float64, Q float64) float64 {
return func(x, y float64) float64 {
return x + y
}
}
Or:
var adder func(x1, x2 float64) float64 = CreateAdder()
While you can use a var or declare a type, you don't need to.
You can do this quite simply:
package main
import "fmt"
var count int
func increment(i int) int {
return i + 1
}
func decrement(i int) int {
return i - 1
}
func execute(f func(int) int) int {
return f(count)
}
func main() {
count = 2
count = execute(increment)
fmt.Println(count)
count = execute(decrement)
fmt.Println(count)
}
//The output is:
3
2
Just a brainteaser with recursive function definition for chaining middlewares in a web app.
First, the toolbox:
func MakeChain() (Chain, http.Handler) {
nop := http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {})
var list []Middleware
var final http.Handler = nop
var f Chain
f = func(m Middleware) Chain {
if m != nil {
list = append(list, m)
} else {
for i := len(list) - 1; i >= 0; i-- {
mid := list[i]
if mid == nil {
continue
}
if next := mid(final); next != nil {
final = next
} else {
final = nop
}
}
if final == nil {
final = nop
}
return nil
}
return f
}
return f, final
}
type (
Middleware func(http.Handler) http.Handler
Chain func(Middleware) Chain
)
As you see type Chain is a function that returns another function of the same type Chain (How first class is that!).
Now some tests to see it in action:
func TestDummy(t *testing.T) {
c, final := MakeChain()
c(mw1(`OK!`))(mw2(t, `OK!`))(nil)
log.Println(final)
w1 := httptest.NewRecorder()
r1, err := http.NewRequest("GET", "/api/v1", nil)
if err != nil {
t.Fatal(err)
}
final.ServeHTTP(w1, r1)
}
func mw2(t *testing.T, expectedState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
val := r.Context().Value(contextKey("state"))
sval := fmt.Sprintf("%v", val)
assert.Equal(t, sval, expectedState)
})
}
}
func mw1(initialState string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), contextKey("state"), initialState)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
type contextKey string
Again, this was just a brainteaser to show we can use first class functions in Go in different ways. Personally I use chi nowadays as router and for handling middlewares.