I have this code
package main
import (
"fmt"
)
type foo struct {
a int
b bool
}
type foos []foo
type bar struct {
foos
}
func newBar() *bar {
b := &bar{
foos: make([]foo, 3, 3),
}
for _, foo := range b.foos {
// didn't set b to true
foo.b = true
}
return b
}
func main() {
b := newBar()
fmt.Println(b)
// set b to true
b.foos[0].b = true
fmt.Println(b)
}
The Go Playground
As you can see I want to initialize bar using constructor newBar() but I want the embed type foo.b is initialize with non zero value so I initialize with for range statement but it didn't work as intended, the foo.b is still false, all of them. As comparison in the main function using this code b.foos[0].b = true it work. So whats wrong with my code?
Omg, I just realized this after posting this question, it's because variable slot is local to for loop. So the solution is:
for i, _ := range b.foos {
// now b is set to true
b.foos[i].b = true
}
Related
This question already has answers here:
How can I access a struct field with generics (type T has no field or method)?
(1 answer)
Generic function to work on different structs with common members from external package?
(1 answer)
Closed 3 months ago.
There are two struct types, Foo and Bar, with an int data member val. I am trying to write a generic function that can handle both types. I tried the following and this did not work.
package main
import "fmt"
type Foo struct {
val int
}
type Bar struct {
val int
}
func Add[T any](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.val
}
return sum
}
func Test() {
f1 := Foo{val: 2}
f2 := Foo{val: 2}
fslice := []Foo{f1, f2}
fsum := Add(fslice)
fmt.Printf("fsum = %d\n", fsum)
b1 := Bar{val: 3}
b2 := Bar{val: 3}
bslice := []Bar{b1, b2}
bsum := Add(bslice)
fmt.Printf("bsum = %d\n", bsum)
}
func main() {
Test()
}
The compiler throws the following error.
$ go run generics1.go
# command-line-arguments
./generics1.go:16:15: elem.val undefined (type T has no field or method val)
Go playground link: https://go.dev/play/p/mdOMH3xuwu7
What could be a possible way to approach this?
Per golang 1.18 release note
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in a future release.
You could define one GetVal() interface method to retrieve the val, and use this method as part of type constraint of generic.
Sample codes
type Foo struct {
val int
}
func (f Foo) GetVal() int {
return f.val
}
type Bar struct {
val int
}
func (b Bar) GetVal() int {
return b.val
}
type MyType interface {
Foo | Bar
GetVal() int
}
func Add[T MyType](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.GetVal()
}
return sum
}
https://go.dev/play/p/0eJZpqy7q8f
If I have a two different structs, that mostly overlap each other in regards to their property types, and I need to create one from the other, is there some more concise way to do so w/o having to verbosely set each and every property?
Example: https://go.dev/play/p/k4TUrWQ7JLD
package main
import (
"fmt"
)
type Foo struct {
A int64
B string
C []string
D []int
// many other properties
}
type Bar struct {
A string
B string
C []int64
D []int
// many other properties
}
func getBarA(a int64) string {
// somhow map an int64 from Foo to a string for Bar
return "A"
}
func getBarC(a []string) []int64 {
// somhow map an int64 from Foo to a string for Bar
return []int64{1, 2, 3}
}
func getABarFromFoo(foo Foo) Bar {
return Bar{
A: getBarA(foo.A),
B: foo.B,
C: getBarC(foo.C),
D: foo.D,
// All the rest of possibly MANY properties :-(
}
}
func main() {
b := getABarFromFoo(Foo{})
fmt.Println(b)
}
As you can imagine, this mapping can get very repetitive/verbose… is there some way to just do something simple like this? (yes, I know this isn’t proper Go)
b:= Bar{
...foo,
A: getBarA(foo.A),
B: getBarC(foo.C),
}
I'm looking/hoping/🙏 for is a way to essentially say:
"Give me a Bar, created entirely from the compatible properties of a given Foo instance.
And for [these] few incompatible properties, here's how to set those."
Well.
b:= Bar{
...foo,
A: getBarA(foo.A),
B: getBarC(foo.C),
}
You can't assign []int64 returned from getBarC to string B. You might want to assign it to C instead.
I think you can't copy like javascript using spread operator. Even if you could, this will cause build error "duplicate field name ". What you can do is to keep a field Foo inside Bar and then convert the instance of Foo, namely foo, to bar which is an instance of Bar.
package main
import (
"fmt"
)
type Foo struct {
A int64
B string
C []string
D []int
// many other properties
}
type Bar struct {
Foo
A string
B string
C []int64
D []int
// many other properties
}
func getBarA(a int64) string {
// somhow map an int64 from Foo to a string for Bar
return "A"
}
func getBarC(a []string) []int64 {
return []int64{1, 2, 3}
}
func getABarFromFoo(foo Foo) Bar {
bar := Bar{Foo: foo}
bar.A = getBarA(foo.A)
bar.C = getBarC(foo.C)
return bar
}
func main() {
b := getABarFromFoo(Foo{})
fmt.Println(b) // just don't sweat over empty Foo inside b
}
If some fields of two different structures overlap somehow, the answer is Object Orientation.
You should think about the relationship between Foo and Bar.
For instance there may share a embed common substructure. But why?
You should only copy and convert parameters. You can serialize/deserialize it to convert from/to any type with given rules.
Perhaps Foo knowns how to convert to Bar. Or Bar have a constructor who accepts Foo. Or Base.
type Base struct{
B string
D [] int
}
type Foo struct {
Base
A string
C []int
}
I am trying to compare these two interfaces together as a function. It is working as far as I am concerned. I am sending a struct in A interface{} and map[string]interface{} in B, having the same values but when being compared with reflect they are not resulting to be the same. I would like to be able to convert the map[string]interface{} into a struct interface inside this function so that my tests can get shorter. I have tried using https://github.com/mitchellh/copystructure, but does not work inside this function.(from outside it works though:
var m map[string]interface{}
var something StructType
err := mapstructure.Decode(m, &something)
if err....
and then i send the something in the B interface)
below is the function to compare the interfaces. You can copy and paste and see how it works for yourself
package main
import (
"log"
"reflect"
)
type Something struct {
Name string
Age int
Male bool
Cars []string
}
func main() {
var s Something
s.Name = "joe"
s.Male = true
s.Age = 20
s.Cars = []string{"Fordd", "Chevy", "Mazda"}
m := make(map[string]interface{})
m["Name"] = "joe"
m["Male"] = true
m["Age"] = 20
m["Cars"] = []string{"Fordd", "Chevy", "Mazda"}
//with map[string]interface{} although the same values it does not work
log.Println("Are these the same: ", CompareData(s, m))
//with struct of same type it works
var s2 Something
s2.Name = "joe"
s2.Male = true
s2.Age = 20
s2.Cars = []string{"Fordd", "Chevy", "Mazda"}
log.Println("Are these the same: ", CompareData(s, s2))
}
func CompareData(A interface{}, B interface{}) bool {
a := reflect.ValueOf(A)
b := reflect.ValueOf(B)
akind := a.Kind().String()
bkind := a.Kind().String()
if akind == "slice" && bkind == "slice" {
for i := 0; i < a.Len(); i++ {
// log.Println("they are sliced")
CompareData(a.Index(i).Interface(), b.Index(i).Interface())
// log.Println("\n", a.Index(i).Interface(), "\n", b.Index(i).Interface())
}
// t.Fatal("this is a slice you need to iterate over the values")
} else {
// log.Println("\n\n", A, "\n", B)
if !reflect.DeepEqual(a.Interface(), b.Interface()) {
log.Println("These should be equal\nSuccessData:\t", a.Interface(), "\nData:\t\t", b.Interface())
return false
}
// log.Println("\nA:\t", A, "\nB:\t", B)
}
return true
}
This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 5 years ago.
I am attempting to assign an array of structs of type Baz to an array of interfaces of type Bar embedded in a second struct of type Foo. I have not been able to find the exact information here or elsewhere googling. I have provided a minimum working example.
I get the following error:
$ go run main.go
./main.go:38: cannot use baz (type []*Baz) as type []Bar in argument to NewFoo
My apologies if my code is not idiomatic go and also if I have not confirmed exactly to standards for posting questions, this is my first post.
package main
import (
"fmt"
)
type Foo struct {
b []Bar
}
type Baz struct {
a, b int
}
type Bar interface {
Multiply() int
}
func (baz *Baz) Multiply() int{
return baz.a * baz.b
}
func NewFoo(bar []Bar) *Foo{
return &Foo{b: bar}
}
func NewBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = &Baz{a: 1, b: 2}
bazes[1] = &Baz{a: 3, b: 4}
return bazes
}
func main() {
baz := NewBaz()
foo := NewFoo(baz)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
UPDATE: I approved the duplicate vote after further reading and understanding the suggested related posts. Thank you to those who pointed me in that direction. For future interested readers, my final implementation consistent with my use case is as follows:
package main
import (
"fmt"
)
type Foo struct {
b []Bar
}
type Baz struct {
a, b int
}
type Bar interface { //
Multiply() int
}
func (baz *Baz) Multiply() int {
return baz.a * baz.b
}
func NewFoo(bar []*Baz) *Foo{
f := &Foo{}
f.b = make([]Bar, 2)
fmt.Println("len(bar) ", len(bar), "len(f.b)", len(f.b) )
for i, _ := range f.b {
f.b[i] = bar[i]
}
return f
}
func MakeBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = NewBaz(1, 2)
bazes[1] = NewBaz(3, 4)
return bazes
}
func NewBaz(aa, bb int) *Baz {
return &Baz{a: aa, b: bb}
}
func main() {
baz := MakeBaz()
foo := NewFoo(baz)
fmt.Printf("%v\n", foo)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
There's a couple of different ways to do this, but the most straightforward is to embed type Baz with Bar. Baz can now multiply() and has two fields (a, b). Your code would look something like this:
package main
import (
"fmt"
)
type Foo struct {
b []*Baz
}
type Baz struct {
Bar
a, b int
}
type Bar interface {
Multiply() int
}
func (baz *Baz) Multiply() int {
return baz.a * baz.b
}
func NewFoo(bar []*Baz) *Foo {
return &Foo{b: bar}
}
func NewBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = &Baz{a: 1, b: 2}
bazes[1] = &Baz{a: 3, b: 4}
return bazes
}
func main() {
baz := NewBaz()
foo := NewFoo(baz)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
GoPlay here:
https://play.golang.org/p/lia0ZS81TO
Great first question, by the way.
The error you are getting:
cannot use baz (type []*Baz) as type []Bar
Is because Go won't let you assign an array of Baz to an array of Bar, even when it'd let you assign a Baz to a Bar variable.
To see this in a more simple form, this works fine:
var oneBaz *Baz = &Baz{a: 1, b: 2}
var oneBar Bar = oneBaz
Because the type Baz satisfies the Bar interface and you can assign a Baz object to a Bar variable.
But this does not work (even if it'd looks like it could work):
var bazArray []*Baz = make([]*Baz, 2)
var barArray []Bar = bazArray
It will throw the same error you are seeing.
In order to make this work, you'd probably need to implement one of the solutions listed in this related question:
Type converting slices of interfaces in go
I'm new to Go programming and wondering what's the difference (if any) there between
a.
func DoSomething(a *A) {
b = a
}
b.
func DoSomething(a A) {
b = &a
}
If you are actually asking what the difference of those b's are, one is a pointer to the object passed as an argument to DoSomething, and the other is a pointer to a copy of the object passed as an argument to DoSomething.
https://play.golang.org/p/ush0hDZsdE
type A struct {
f string
}
func DoSomethingPtr(a *A) {
b := a
b.f = "hi"
}
func DoSomething(a A) {
b := &a
b.f = "hey"
}
func main() {
x := A{"hello"}
DoSomething(x)
fmt.Println(x)
DoSomethingPtr(&x)
fmt.Println(x)
}
The variable b would be assigned a different value in each function. The values are different because one is passing a copied value and the other is passing a pointer to the original value in memory.
package main
import "fmt"
type A string
func DoSomethingPtr(a *A) {
fmt.Println(a)
}
func DoSomething(a A) {
fmt.Println(&a)
}
func main() {
x := A("hello")
DoSomething(x)
DoSomethingPtr(&x)
}
Here is the executable proof.
In general, these two functions will assign different values to b. The second one makes a copy of the argument, and so the a inside the function generally has a different memory address than whatever input is passed into the function. See this playground example
package main
type A struct{
x int
}
var b *A
func d(a *A) {
b = a
}
func e(a A) {
b = &a
}
func main() {
var a = A{3}
println(&a)
d(&a)
println(b)
e(a)
println(b)
}
Interestingly, if you make the type A an empty struct instead, and initialize var a = A{}, you actually see the same value for b in the println statements.
That's because for the empty-struct type, there can only really only ever be 1 value, and its immutable, so all instances of it share the same memory address?