I am moving to Go from Node.js and I am concerned whether a construct that I would use in Node is safe to do in Go and whether there is a more idiomatic way to accomplish the same thing. I am using the Echo framework and want to set a route specific struct that will be available within the context object. I could generate the struct for every call within middleware, but it's expensive to do so. Instead, I set the struct once in an outer func that then returns an inner func that refers to the struct in the outer func. My hope is that I then only incur the generation cost once and then have the correct struct associated with my route for every call.
e.POST(path, POST.GenericPostHandler, func(next echo.HandlerFunc) echo.HandlerFunc {
operation := getOperationMap(path)
return func(c echo.Context) error {
c.Set("op", operation)
return next(c)
}
})
Are there any concerns with this code? Will it cause problems with GC? Is there a more efficient way to accomplish the same thing? I assume a copy of the struct is made every time the middleware is called.
This code is safe, won't cause GC problems, and is a good, idiomatic pattern that can be used in Go.
In your example, only one operation will be created, moved to the heap, and then shared by each request as they are handled by Echo.
I often use this exact pattern myself when I need to initialize an expensive struct that will be used when handling all requests.
If operationMap never changes after initialization, You can declare operationMap as a singleton instance like following:
package main
import (
"fmt"
"sync"
)
var (
operationMapInst map[string]string // I don't know the exact type of map, so you should change the type.
operationMapOnce sync.Once
)
func getOperationMap() map[string]string {
// operationMapOnce.Do() runs only once
// when the first time getOperationMap() is called.
operationMapOnce.Do(func() {
// Initialize operationMapInst.
operationMapInst = map[string]string{"/": "root", "/ver": "version"}
fmt.Println("operaionMap has initialized!")
})
return operationMapInst
}
func main() {
// The initialization logic runs only once.
// Because getOperationMap() returns map,
// syntax for the value for a path should be getOperationMap()[path],
// not getOperationMap(path).
rootOp, ok := getOperationMap()["/"]
fmt.Println(rootOp, ok)
// repetition
rootOp, ok = getOperationMap()["/"]
fmt.Println(rootOp, ok)
verOp, ok := getOperationMap()["/ver"]
fmt.Println(verOp, ok)
verOp, ok = getOperationMap()["/ver"]
fmt.Println(verOp, ok)
}
You can run this code here.
I recommend http://marcio.io/2015/07/singleton-pattern-in-go/ for understanding singleton pattern in Go.
Related
I'm surprised to see the lack of (in any) modules for a configuration module in Go which is thread safe for concurrent reads/writes.
I'm surprised there is no easy method to basically have something like https://github.com/spf13/viper, but thread safe.. where the Get/Set holds a Lock.
what's the right Go way to handle this without bloating code?
I normally use: https://github.com/spf13/viper however if the program for example as a GUI configuration is changeable during runtime, this package doesn't work.
I started doing the following
var config struct {
lock sync.RWMutex
myString string
myInt int
}
func main() {
config.lock.RLock()
_ = config.myString // any read
config.lock.RUnlock()
}
however this becomes very very tedious when accessing members to each time Lock/Unlock every single access for a read or a write and code becomes bloated and repetitive.
I typically use a configuration struct that is retrieved and updated atomically. This allows multiple fields to be updated in a single "transaction" and is easy to implement/use.
With Go1.18 and earlier this can be implemented with atomic.Value and wrap with some simple helper functions to convert the type from interface{} to your *config.
It is even simpler with atomic.Pointer in Go 1.19:
package main
import (
"sync/atomic"
)
type config struct {
str string
num int
}
var cfg atomic.Pointer[config]
func main() {
// Store initial configuration.
cfg.Store(&config{str: "foo", num: 42})
// Clone and modify multiple fields.
newCfg := *cfg.Load()
newCfg.str = "bar"
newCfg.num++
cfg.Store(&newCfg)
// Retrieve a value.
_ = cfg.Load().str
}
With Go1.18 and earlier you can use atomic.Value and wrap them with some simple helper functions to convert the type from interface{} to your *config.
I am trying to create a Map with String and functions as key and Value. It works if all functions are of same signature but my requirement is to store functions of different signature in the same map. Is this possible in Go?
package main
import "fmt"
func main() {
functions := buildFunctions()
f := functions["isInValid"]
// f("hello")
}
func buildFunctions() map[string]func() bool {
functions := map[string]func() bool{
"isInValid": isInValid,
"isAvailable": isAvailable,
}
return functions
}
func isInValid(s string) bool {
fmt.Println("Invalid ", s)
return true
}
func isAvailable(s string, s1 string) bool {
return true
}
https://play.golang.org/p/ocwCgEpa_0G
Go is a strongly typed language. So, it's not possible the way, it is possible with, say python. But just like python, once you do this, you loose the benefit of compile time error checks, and your runtime error checking has to be full-proof.
Here's what you can do:
Use map[string]interface{} type for your function map, which enables you to store anything. But then you are responsible to correctly type assertion at the time of calling. Problem is that, in most cases, if while calling a function, you could know the type of function, may be you might not need a map in the first place.
Use a map[string]string or map[string]interface{} as the argument, and return type in all the functions that are supposed to go into this map. Or at least put all the variable arguments into this map.
eg.
map[string](func (name string, age int, other_attributes
map[string]interface{}) (map[string]interface{}, error))
But again, each function call should provide the correct arguments, and there should also be checks inside the functions, to see (with non-panic version of map lookup), if the parameters are correctly provided, if not, you can return a custom error like ErrInvalidParametersPassed. (playing the role of an interpreter). But you will still have lesser chances of messing up, compared to first option. As the burden of type assertion will be on the function implementation, and not the caller. Caller just needs to fetch it's required values, which it anyways needs to know about.
But yet, best option would be to redesign your actual solution in a way, so that it can be done without going this road. As #bereal suggested in comments, it's good to have separate maps if possible, or maybe use a superset of arguments if they aren't too different, or too many. If there are just a few arguments, even switch case could be clean enough. Look for ways that cheat/bypass compile time checks, when you are truly convinced that there is no other elegant way.
I am passing a pointer to a string, to a method which takes an interface (I have multiple versions of the method, with different receivers, so I am trying to work with empty interfaces, so that I don't end up with a ton of boilerplate madness. Essentially, I want to populate the string with the first value in the slice. I am able to see the value get populated inside the function, but then for some reason, in my application which calls it, tha value doesn't change. I suspect this is some kind of pointer arithmetic problem, but could really use some help!
I have the following interface :
type HeadInterface interface{
Head(interface{})
}
And then I have the following functions :
func Head(slice HeadInterface, result interface{}){
slice.Head(result)
}
func (slice StringSlice) Head(result interface{}){
result = reflect.ValueOf(slice[0])
fmt.Println(result)
}
and... here is my call to the function from an application which calls the mehtod...
func main(){
test := x.StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
x.Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println(result)
}
*NOTE : I am aware that getting the first element doesn't need to be this complicated, and could be slice[0] as a straight assertion, but this is more of an exercise in reusable code, and also in trying to get a grasp of pointers, so please don't point out that solution - I would get much more use out of a solution to my actual problem here * :)
As you said in your NOTE, I'm pretty sure this doesn't have to be this complicated, but to make it work in your context:
package main
import (
"fmt"
"reflect"
)
type HeadInterface interface {
Head(interface{})
}
func Head(slice HeadInterface, result interface{}) {
slice.Head(result)
}
type StringSlice []string
func (slice StringSlice) Head(result interface{}) {
switch result := result.(type) {
case *string:
*result = reflect.ValueOf(slice[0]).String()
fmt.Println("inside Head:", *result)
default:
panic("can't handle this type!")
}
}
func main() {
test := StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println("outside:", result)
}
The hard part about working with interface{} is that it's hard to be specific about a type's behavior given that interface{} is the most un-specific type. To modify a variable that you pass as a pointer to a function, you have to use the asterisk (dereference) (for example *result) on the variable in order to change the value it points to, not the pointer itself. But to use the asterisk, you have to know it's actually a pointer (something interface{} doesn't tell you) so that's why I used the type switch to be sure it's a pointer to a string.
I've heard many times that you should avoid global variables.
In my example I declared a global myTypes variable only to avoid declaring that variable over and over again in a function call or something similar.
Is this how it should be done? Is there a better way? A more testable way?
var myTypes = map[string]string{
"type1": "tpl1",
"type2": "tpl2",
}
func AFunc(someType string) string {
fmt.Sprintf("this is your type %s", myTypes[someType])
}
func main() {
AFunc("type1")
}
Not all global variables are bad. In your case:
The global variable is in the main package and therefore only accessible by a single program. This is ok.
The global variable is initialized once and not modified thereafter. This is ok.
On the other hand, whenever a global variable is modified during the program’s execution, the program becomes more difficult to understand. Therefore it should be avoided.
In a package that is meant to be reusable, global variables should be avoided since then two users of that package might influence each other. Imagine if the json package had a global variable var Indent bool. Such a variable is better to be hidden inside a data structure like JsonFormatter that gets created anew each time someone wants to format some JSON.
One usual way is to use Method Value
Consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
The expression
T.Mv
yields a function equivalent to Mv but with an explicit receiver as its first argument; it has signature
func(tv T, a int) int
You can see an example of Method Value in this thread
// TODO: Get rid of the global variable.
var foo service
func handleFoo(w http.ResponseWriter, req *http.Request) {
// code that uses foo
}
func main() {
foo = initFoo()
http.HandleFunc("/foo", handleFoo)
}
One way to get rid of that global variable is to use method values:
type fooHandler struct {
foo service
}
func (h fooHandler) handle(w http.ResponseWriter, req *http.Request) {
// code that uses h.foo
}
func main() {
foo := initFoo()
http.HandleFunc("/foo", fooHandler{foo}.handle)
}
A new official approach for your global values is introduced in Go 1.7 with context.Context#Values.
Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions.
See "How to correctly use context.Context in Go 1.7"
Finally, in addition of being hard to test, global values can prevent vendoring.
See "To vendor or not to vendor, that is a question"
Many Go’s libaries have exported package variables. Those variables can be viewed as certain global states of a certain package.
Prior vendoring era, we can go get each imported package once and the global state of each imported package can be shared within all other imported packages.
Some devs may take it as granted and simply manipulate those global states at will.
However, with vendoring each imported package may have its own view of global states. Now a dev may found it impossible to change other package’s view of global state
You're not modifying myTypes, just reading it, so it's not a variable at all, it's a constant, and would be defined as such if Go supported it (and make sure you don't mutate it -- unfortunately Go doesn't allow you to enforce "constness" like other languages do). Global constants are mostly fine.
If you were to modify myTypes, e.g. by providing a function to add new types at runtime, then yes, it's a bad idea to retain myTypes as global state. You might just get away with it as long as you do it only in your "main program" which you're sure will never be a package to be imported by other code, but you don't know where this code might end up / get copied to (or even just used from multiple places in the same package), so why risk it. If this becomes a package that gets imported by other packages, things may work fine as long as there's not more than one such "client" package is active at runtime, but as soon as somebody links together several such packages into one binary, all those user packages will stomp over each other's data in the global myTypes. If a client package expects to only see the myTypes that it put in earlier, this will break if there's another client with different expectations. So packages that work fine when used individually may break when used together, with no way to fix this except changing the shared code. So just don't do it. It's a shame that Google themselves use global state in some of their own public stuff, e.g. in the standard "flag" package and things like "glog" which uses it and thus inherits the problem. Don't do it.
this code works fine but the temp var used to call the function feels clunky
package main
import "fmt"
type Foo struct {
name string
value int
}
// SetName receives a pointer to Foo so it can modify it.
func (f *Foo) SetName(name string) {
f.name = name
}
var users = map[string]Foo{}
func main() {
// Notice the Foo{}. The new(Foo) was just a syntactic sugar for &Foo{}
// and we don't need a pointer to the Foo, so I replaced it.
// Not relevant to the problem, though.
//p := Foo{}
users["a"] = Foo{value: 1}
x := users["a"]
x.SetName("Abc")
users["a"] = x
fmt.Println(users)
}
http://play.golang.org/p/vAXthNBfdP
Unfortunately no. In Go typically pointers are transparent, and values get auto-addressed when you call pointer methods on them. You managed to find one of the few cases where they aren't. That case is map storage -- values in maps are not considered addressable. That is, you can never do val := &map[key].
When you have a value val := Typ{} and methods defined on *Typ, when you try to call val.Method() Go will super secretly do (&val).Method(). Since you can't do &map[key], then this doesn't work so that temporary variable dance you do is the only way.
As for why that's the case, the internals of a map are considered a bit secret to the user, since it's a hashmap it reserves the right to reallocate itself, shuffle around data, etc, allowing you to take the address of any value undermines that. There have been proposals considered to allow this specific case to work (that is: calling a method with a pointer receiver on it), since the fix is so easy, but none have been accepted yet. It may be allowed someday, but not right now.
Following Jsor’s detailed explanation: if you really need to call methods of map values, it seems the only way for now is to use pointers for values.
var users = make(map[string]*Foo)
func main() {
users["a"] = &Foo{value: 1}
users["a"].SetName("Abc")
fmt.Println(users["a"])
}
But that loses you, precisely, the ability to meaningfully print them (values are just memory addresses now). You’d need to write a custom printing function for *Foo:
func (f *Foo) String() string {
return fmt.Sprintf("%v", *f)
}
http://play.golang.org/p/6-y2ewdnre