I'm working on my first real Go project and have been searching for some tools to handle the configuration.
Finally, I've found this tool: https://github.com/spf13/viper which is really nice but I have some issues when I try to handle some more complex configurations such as the following config.yaml example:
app:
name: "project-name"
version 1
models:
modelA:
varA: "foo"
varB: "bar"
modelB:
varA: "baz"
varB: "qux"
varC: "norf"
I don't know how to get the values from modelB for example. While looking at the lib code, I've found the followings but I don't really understand how to use it:
// Marshals the config into a Struct
func Marshal(rawVal interface{}) error {...}
func AllSettings() map[string]interface{} {...}
What I want is to be able, from everywhere in my package, to do something like:
modelsConf := viper.Get("models")
fmt.Println(modelsConf["modelA"]["varA"])
Could someone explain me the best way to achieve this?
Since the "models" block is a map, it's a bit easier to call
m := viper.GetStringMap("models")
m will be a map[string]interface {}
Then, you get the value of m[key], which is an interface {}, so you cast it to map[interface {}]interface {} :
m := v.GetStringMap("models")
mm := m["modelA"].(map[interface{}]interface{})
Now you can access "varA" key passing the key as an interface {} :
mmm := mm[string("varA")]
mmm is foo
You can simply use:
m := viper.Get("models.modelA")
or
newViperForModelA := viper.Sub("models").Sub("modelA")
Related
So I'm super new to Golang and seeing as the big buzz around the language seems to be concurrency I figured a good way to get my toes wet would be to write a generalized map function. In psudo code:
map(F funtion,A array){
return([F(k) for k in A])
}
And obviously I want the calculations for each F(k) occur concurrently. For organization I have a main file with my implementation and a supporting file Mr with my required definitions.
.
├── main.go
└── Mr
└── Mr.go
Main is a simple test implementation which should convert an array of strings to an array of ints where each member of the result is the length of the corresponding string in the input array.
package main
import(
"fmt"
"./Mr"
)
func exfunc(i int, c chan int){
c<-i
}
func main(){
data := make(map[int]string)
data[1]="these"
data[2]="are"
data[3]="some"
data[4]="words"
data[5]="and a few more..."
f := func(w string)int{
return(len(w))
}
testMr := Mr.Map(f,data) // this is line 22 (matters later)
fmt.Println(testMr)
}
Which works great with my Mr.Map function given that I specify all the types explicitly.
package Mr
type result struct{
key,value int
}
func wrapper(f func(string) int,k int,v string, c chan result){
c <- result{k,f(v)}
}
func Map(f func(string) int,m map[int]string) map[int]int{
c := make(chan result)
ret := make(map[int]int)
n := 0
for k := range m{
go wrapper(f,k,m[k],c)
n++
}
for ;n>0; {
r := <-c
ret[r.key]=r.value
n--
}
return(ret)
}
However I was hoping that I would be able to generalize this mapping with the empty interface.
package Mr
type T interface{}
type result struct{
key,value T
}
func wrapper(f func(T) T,k T,v T, c chan result){
c <- result{k,f(v)}
}
func Map(f func(T) T,m map[T]T) map[T]T{
c := make(chan result)
ret := make(map[T]T)
n := 0
for k := range m{
go wrapper(f,k,m[k],c)
n++
}
for ;n>0; {
r := <-c
ret[r.key]=r.value
n--
}
return(ret)
}
Unfortunately when I run main with this generalize Mr.Map I get the following error.
# command-line-arguments
./main.go:22: cannot use f (type func(string) int) as type func(Mr.T) Mr.T in argument to Mr.Map
./main.go:22: cannot use data (type map[int]string) as type map[Mr.T]Mr.T in argument to Mr.Map
So yeah, obviously I understand what the errors are telling me but it seems wild that I would have to re-write my Map function for each possible combination of key and value types.
Is there a work around here, or is this just the nature of the beast?
No real workaround there, that's the nature of the beast.
The language was designed after struggling with C++ for some time, and the idea of the creators was simplifying all non-vital things but at the same time make key additions to make the language more expressive.
You can read a bit about their reasoning here, which I believe is quite interesting even if you don't agree with all the decisions they made:
https://commandcenter.blogspot.com.ar/2012/06/less-is-exponentially-more.html
In your example, if you wanted to, you could make your maps and functions use interface{} (which by the way is called the empty interface and not "nil" interface).
But of course you would lose compile-time type checking and would have to add casts all around.
You can also try to find an interface to express the commonalities of the types you want to use (which might not be so easy or even possible at all), and then build your mapping API around that interface.
The philosophy of Go is not compatible with generalized functions such as is the style with popular dynamic languages. To properly inform the compiler of what you are trying to do, you should express your needed map through an interface or simply by writing it for each type you are using it with.
Mapping requires allocating an array, iterating through a collection, and adding to the array some data element for each element in the collection. If you need a map for a slice of structs, as is common in the application layer, you can express this tersely in Go:
https://play.golang.org/p/pk3Tl_BdlD
Dynamic languages build a "type tree" of "generic" types that allow for terse programming, such as functions like map being called by one symbol over any possible type. This provides a ton of developer productivity because code can be written loosely to allow easy experimentation.
Go is designed for writing semi-permanent software. It performs well because it requires more information to be supplied to the compiler. Map is only about three lines of code, so the cost/benefit of developer productivity v. efficiency lands on the performance side for Go. Functions like map, reduce and filter should be written explicitly as needed.
To evaluate the language, I would encourage you to try to solve a problem with a Go program and see where that takes you.
I have a function:
func ReturnTuples(map_ map[interface{}]interface{}) [][]interface{} {
In which I'm trying to call like this:
m := make(map[string]int)
m["k1"] = 7
m["k2"] = 13
fmt.Println(ReturnTuples(m))
But I'm getting
cannot use m (type map[string]int) as type map[interface {}]interface {} in argument to ReturnTuples
Shouldn't it work since string and int both implement interface{}?
I've searched and the best I could find was Convert map[interface {}]interface {} to map[string]string but it won't answer why I cannot use m as an argument.
I also believe that if the argument of the function were only interface{} it would work too, since map[something][something] implements interface, right? What is the best way to do it, and why it won't work in my case?
A solution to your problem, simply initiate the map as an empty interface of empty interfaces:
m := map[interface{}]interface{}
then you can assign any type key or value you want in the 'ReturnTuples' function.
playground example
NOTE: remember that if you want to use the values later as the original types, you will need to use type assertion because now they are of type interface{}
You may do something this like this, were anything is one map value which you can get using a for loop:
switch v := anything.(type) {
case string:
fmt.Println(v)
case int32, int64:
fmt.Println(v)
case string:
fmt.Println(v)
case SomeCustomType:
fmt.Println(v)
default:
fmt.Println("unknown")
}
If you are looking for an explanation for the "why"
#ymonad gave a full answer so I wont repeat it again.
hope it make sense
PS: don't get the down votes on the question, a legit one in my eyes...
You can type assert in the function itself.
func test(m interface{},key interface{}) bool { // Map is passed as reference
ma := m.(map[interface{}]interface{})
if _, ok := ma[key]; ok == false {
....
}
A validator package gives me back strings like this if a given field in my struct doesn't pass the validation:
myString := "Stream.Fields[0].Name"
How can i use this string to gain access to the struct field specified in it? I need to reference it somehow but i have no idea where to start with.
I'm beginning to learn Go and already came across the "Reflect" package which seems to be able to do that but i don't know what to look for or how to formulate the right question.
You need to use reflect package for this.
Here I have written a sample function which given an instance and string key like Stream.Details.Name will return the Name from the field Details of instance Stream
This works for structs without array or map operators , just the . operator . You may extend this to support the [] aswell
func getValueFromStruct(keyWithDots string, object interface{}) (interface{}, error) {
keySlice := strings.Split(keyWithDots, ".")
v := reflect.ValueOf(object)
// iterate through field names ,ignore the first name as it might be the current instance name
// you can make it recursive also if want to support types like slice,map etc along with struct
for _, key := range keySlice[1:] {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("only accepts structs; got %T", v)
}
v = v.FieldByName(key)
}
return v, nil
}
Here is golang play link : https://play.golang.org/p/NIRdGONZBhP
This library also exists, which might do what you want:
https://github.com/mcuadros/go-lookup
The lib uses the reflect package under the hood.
I have the following code:
func returnTheMap() map[string][]string{
myThing := getSomeValue()
}
getSomeValue() returns something of type map[string]interface{}
but it is always internally a map[string][]string.
What is the best way to set myThing equal to the same thing as getSomeValue(), but of type map[string][]string?
I can make a new object like so:
newMap := make(map[string][]string)
// cardTypeList is of type map[string]interface {}, must convert to map[string][]string
for k, v := range myThing {
newMap[k] = v.([]string)
}
but is there any way to do this in-place, or is there any preferred way to do this?
According to Go FAQ, you cannot change the type of slice directly.
So it seems that your solution is the preferred way.
Is getSomeValue() your function? If so, I would change the return type to be map[string][]string rather than map[string][]interface.
If that is not the case, I would create some helpers to go through and check to make sure the types are set to your needs. I have an example in the playground
https://play.golang.org/p/9OPgXGXADY
Hello I'm about to port my two almost working simple fuse filesystems from bazillion fuse to go-fuse. go-fuse api seems more complex.
The question is:
In NewServer(), which RawFileSystem to use?
How to implement callbacks for read, readdir etc.?
Where to use WaitMount()?
What are DeleteNotify(), EntryNotify()?
ok i found the solutions
1.
make a struct that contains nodefs.Node:
type my_root struct {nodefs.Node}
initialize it
my = &my_root{Node: nodefs.NewDefaultNode()}
make a connection and a raw filesystem
con := nodefs.NewFileSystemConnector(my, nil)
raw := fuse.NewRawFileSystem(con.RawFS())
finally, fire up the fuse fs
server, err := fuse.NewServer(raw, f.dir, optz)
like this:
func (my_root) OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {}
func (my_root) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node *nodefs.Inode, code fuse.Status)
after step 1, like this:
server.WaitMount()
i didn't need this.