I have a struct composed of multiple fields of same type.
type test struct{
A int
B int
C int
}
I want to apply a function that does the same things to the three fields, but I only wanna do it on one each time.
function something (toto test, cond int) {
if (cond == 1){
// then we will use A for the rest of the function
}else if (cond == 2) {
// then we use B etc....
} ...
for mail, v := range bdd {
if _, ok := someMap[v.A]; !ok { // use v.A or V.B or V.C
delete(bdd, mail)
}
...
}
...
}
The function is really long and I it bothers me to have the code duplicated like 3 times just for one line that changes.
I tried things with the reflect package. I think it's a dangerous idea to go into that.
In your situation I'd use map instead of struct, but if struct is really required you can use reflect package.
v := reflect.ValueOf(x)
for i := 0; i < v.NumField(); i++ {
fmt.Printf("%v", v.Field(i).Interface())
}
Related
I would like to loop through a slice of structs, and populate a struct field (which is a map) by passing in each struct to a function.
I have the below struct
type thing struct {
topicThing map[string]int
}
and I have the below functions
func main() {
ths := make([]thing, 0)
for i := 0; i < 10; i++ {
var th thing
ths = append(ths, th)
}
for _, th := range ths {
dothing(&th)
}
for _, th := range ths {
fmt.Println(th.topicThing)
}
}
func dothing(th *thing) {
tc := make(map[string]int)
tc["Hello"] = 1
tc["Bye"] = 2
th.topicThing = tc
}
The main function creates a slice of things (refered as ths), and passes each thing to the dothing() function by iterating over them.
Within dothing(), I create a new map, populate it with data, and assigns it to the passed in thing's attribute. However, by the time we iterate over ths in the main function to print topicThing of each thing, the map is empty.
Since make() creates objects within the heap, I was hoping it would be accessible even outside of the function scope. Can anyone tell me why this is happening?
P.S.
if I change the dothing() function like below:
func dothing(th *thing) {
th.topicThing["Hello"] = 1
th.topicThing["Bye"] = 2
}
The code works as expected, meaning the map is populated with data when accessed in the main function.
The range copies your object.
So when you do this,
for _, th := range ths {
dothing(&th)
}
you are actually dothing on a copy.
For example, with this main:
func main() {
ths := make([]thing, 0)
for i := 0; i < 10; i++ {
var th thing
ths = append(ths, th)
}
for _, th := range ths {
dothing(&th)
fmt.Println(th.topicThing)
}
it will print the right thing, since we are still working on the copy.
In order to not copy, use the array index:
for idx, _ := range ths {
dothing(&ths[idx])
}
tl;dr
I have an arbitrary directed graph defined by a Node struct.
I now want to be able to provide a way to write functions that walk this graph and "tag" each Node with metadata specific to that function.
For example, consider a function to count the number of nodes:
type Node struct {
Nexts []*Node
}
func CountNodes(root *Node) int {
m := make(map[*Node]bool)
return countNodesHelper(root, m)
}
func countNodesHelper(root *Node, m map[*Node]bool) int {
_, seen := m[root]
if seen {
return 0
}
m[root] = true
c := 1
for _, child := range root.Nexts {
c += countNodesHelper(child, m)
}
return c
}
func main() {
n1 := &Node{make([]*Node, 0, 1)}
n2 := &Node{[]*Node{n1}}
n1.Nexts = append(n1.Nexts, n2)
fmt.Println(CountNodes(n1))
}
I could rewrite this if I added a "seen" tag inside the struct:
type NodeWithTag struct {
Nexts []*NodeWithTag
Seen bool
}
func CountNodesWithTag(root *NodeWithTag) int {
if root.Seen {
return 0
}
root.Seen = true
c := 1
for _, child := range root.Nexts {
c += CountNodesWithTag(child)
}
return c
}
func main() {
n1 := &NodeWithTag{make([]*NodeWithTag, 0, 1), false}
n2 := &NodeWithTag{[]*NodeWithTag{n1}, false}
n1.Nexts = append(n1.Nexts, n2)
fmt.Println(CountNodesWithTag(n1))
}
But the Seen tag isn't enough for, say, a DFS on a tree where I also want to find backwards edges (you need to count up to 2 -- never seen, seen, seen a second time along a a single path). So, I want some way to allow the function's implementation to use it's own type to tag the struct with. A rough equivalent of:
type Node struct {
...
// Not valid golang
void* tag
}
but safer that a void* -- The function should be able to statically verify that the tag is the current type that it expects. Is there a way to do this / an alternative approach.
The reason I want to associate the tag with the Node (rather than a separate map / store of the tags) is to allow easy parallelization of the functions that use such tags, farming out the nodes to different goroutines. In the first approach, the map would have to be shared between the goroutines, and this would quickly become a bottleneck because it will require synchronized access.
If you need to support arbitrary data types, you'll need to use an empty interface:
type NodeWithTag struct {
Nexts []*NodeWithTag
Tag interface{}
}
You can assign any value to the Tag field. If you want to verify that the value is a certain type, say MyType, you can use a type assertion:
myVal, ok := node.Tag.(MyType)
If the value is of that type, ok will be true and myVal will contain the typed value.
I want to know is there a generic way to write code to judge whether a slice contains an element, I find it will frequently useful since there is a lot of logic to fist judge whether specific elem is already in a slice and then decide what to do next. But there seemed not a built-in method for that(For God's sake, why?)
I try to use interface{} to do that like:
func sliceContains(slice []interface{}, elem interface{}) bool {
for _, item := range slice {
if item == elem {
return true
}
}
return false
}
I thought interface{} is sort of like Object of Java, but apparently, I was wrong. Should I write this every time meet with a new struct of slice? Isn't there a generic way to do this?
You can do it with reflect, but it will be MUCH SLOWER than a non-generic equivalent function:
func Contains(slice, elem interface{}) bool {
sv := reflect.ValueOf(slice)
// Check that slice is actually a slice/array.
// you might want to return an error here
if sv.Kind() != reflect.Slice && sv.Kind() != reflect.Array {
return false
}
// iterate the slice
for i := 0; i < sv.Len(); i++ {
// compare elem to the current slice element
if elem == sv.Index(i).Interface() {
return true
}
}
// nothing found
return false
}
func main(){
si := []int {3, 4, 5, 10, 11}
ss := []string {"hello", "world", "foo", "bar"}
fmt.Println(Contains(si, 3))
fmt.Println(Contains(si, 100))
fmt.Println(Contains(ss, "hello"))
fmt.Println(Contains(ss, "baz"))
}
How much slower? about x50-x60 slower:
Benchmarking against a non generic function of the form:
func ContainsNonGeneic(slice []int, elem int) bool {
for _, i := range slice {
if i == elem {
return true
}
}
return false
}
I'm getting:
Generic: N=100000, running time: 73.023214ms 730.23214 ns/op
Non Generic: N=100000, running time: 1.315262ms 13.15262 ns/op
You can make it using the reflect package like that:
func In(s, e interface{}) bool {
slice, elem := reflect.ValueOf(s), reflect.ValueOf(e)
for i := 0; i < slice.Len(); i++ {
if reflect.DeepEqual(slice.Index(i).Interface(), elem.Interface()) {
return true
}
}
return false
}
Playground examples: http://play.golang.org/p/TQrmwIk6B4
Alternatively, you can:
define an interface and make your slices implement it
use maps instead of slices
just write a simple for loop
What way to choose depends on the problem you are solving.
I'm not sure what your specific context is, but you'll probably want to use a map to check if something already exists.
package main
import "fmt"
type PublicClassObjectBuilderFactoryStructure struct {
Tee string
Hee string
}
func main() {
// Empty structs occupy zero bytes.
mymap := map[interface{}]struct{}{}
one := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "hey"}
two := PublicClassObjectBuilderFactoryStructure{Tee: "hola", Hee: "oye"}
three := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "again"}
mymap[one] = struct{}{}
mymap[two] = struct{}{}
// The underscore is ignoring the value, which is an empty struct.
if _, exists := mymap[one]; exists {
fmt.Println("one exists")
}
if _, exists := mymap[two]; exists {
fmt.Println("two exists")
}
if _, exists := mymap[three]; exists {
fmt.Println("three exists")
}
}
Another advantage of using maps instead of a slice is that there is a built-in delete function for maps. https://play.golang.org/p/dmSyyryyS8
If you want a rather different solution, you might try the code-generator approach offered by tools such as Gen. Gen writes source code for each concrete class you want to hold in a slice, so it supports type-safe slices that let you search for the first match of an element.
(Gen also offers a few other kinds of collection and allows you to write your own.)
Given a struct like so:
type B struct {
X string
Y string
}
type D struct {
B
Z string
}
I want to reflect on D and get to the fields X, Y, Z.
Intuitively, before attempting the solution, I was assuming I would be able to traverse the struct D and get all fields using reflection (X, Y, Z) and won't have to deal with B.
But as you can see, I only see the embedded struct B using reflection and not its fields.
http://play.golang.org/p/qZQD5GdTA8
Is there a way I can make B fully transparent when reflecting on D?
Why do I want this?
Imaging a common struct (B in the example here), that is used in multiple other structs by using embedding. Using reflection, the attempt is to copy D into another similar struct in a different package. The destination struct for copying will have all attributes flatly laid out (no embedding there). So there is a mismatch from the source to the destination (embedding vs no embedding) but all the attributes flatly laid out are the same. I don't want to create custom solutions for each struct.
The 'transparency' you expected is just syntactic sugar and has nothing to do with the data representation. If you want to have a function that flattens your data structure, you would have to write it by yourself.
For example (On play):
func DeepFields(iface interface{}) []reflect.Value {
fields := make([]reflect.Value, 0)
ifv := reflect.ValueOf(iface)
ift := reflect.TypeOf(iface)
for i := 0; i < ift.NumField(); i++ {
v := ifv.Field(i)
switch v.Kind() {
case reflect.Struct:
fields = append(fields, DeepFields(v.Interface())...)
default:
fields = append(fields, v)
}
}
return fields
}
Use the following code to collect all promoted field names as keys in map m:
func collectFieldNames(t reflect.Type, m map[string]struct{}) {
// Return if not struct or pointer to struct.
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return
}
// Iterate through fields collecting names in map.
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
m[sf.Name] = struct{}{}
// Recurse into anonymous fields.
if sf.Anonymous {
collectFieldNames(sf.Type, m)
}
}
}
Use it like this:
m := make(map[string]struct{})
collectFieldNames(reflect.TypeOf((*D)(nil)), m)
for name := range m {
fmt.Println(name)
}
Run it on the playground.
This program prints X, Y an Z as requested in the question, but also B because B is also a field name.
This function in this answer can be improved:
Don't blow up on recursive type definitions.
Do not include names repeated at the same level in the hierarchy.
The typeField function in encoding/json/encode.go handles both of these issues.
I have a function that initializes an array of structs from an array of an array of values. This is how I'm doing it currently:
type Loadable interface {
Load([]interface{})
}
type FooList struct {
Foos []*Foo
}
func (fl *FooList) Load(vals []interface{}) {
fl.Foos = make([]*Foo, len(vals))
for i, v := range vals {
foo := &Foo{}
foo.Load(v.([]interface{}))
fl.Foos[i] = foo
}
}
This works just fine, but now I also need to initialize BarLists and BazLists which contain Bars and Bazs. Instead of sprinkling the same snippet throughout my code which all look like this:
type BarList struct {
Bars []*Bar
}
func (fl *BarList) Load(vals []interface{}) {
fl.Bars = make([]*Bar, len(vals))
for i, v := range vals {
bar := &Bar{}
bar.Load(v.([]interface{}))
fl.Bars[i] = bar
}
}
What's the correct way to refactor this code to make it more DRY?
The code you show does not violate the DRY principle. The code implementing the Loader interface (I refuse to write the javaism you used) for type FooList and BarList shares only one line - the range statement. Otherwise they're type specific.
As Go has no generics, there's no direct way how to not write type specialized versions in a generic way (modulo poor choices like everything is an interface{} etc. and/or slowing down your code 10 times by using reflection.)
The simplest I can come up with using reflection would be something like this (not tested):
import "reflect"
// example_of_type should be an instance of the type, e.g. Foo{}
// returns slice of pointers, e.g. []*Foo
func Load(vals []interface{}, example_of_type interface()) interface{} {
type := reflect.TypeOf(example_of_type)
list := reflect.MakeSlice(type.PtrOf().SliceOf(), len(vals), len(vals))
for i, v := range vals {
bar := reflect.New(type)
bar.Interface().(Loadable).Load(v.([]interface{}))
list.Index(i).Set(bar)
}
return list.Interface()
}
You would use it like:
fl.Foos = Load(vals, Foo{}).([]*Foo)
fl.Bars = Load(vals, Bar{}).([]*Bar)