Golang: convert struct to embedded at offset 0 struct - go

I have some different structs like Big with Small embedded at offset 0.
How can I access Small's structure fields from code, that doesn't know anything about Big type, but it is known that Small is at offset 0?
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
var v interface{} = Big{}
// here i only know about 'Small' struct and i know that it is at the begining of variable
v.(Small).val // compile error
It seems that compiler is theoretically able to operate such expression, because it knows that Big type has Small type embedded at offset 0. Is there any way to do such things (maybe with unsafe.Pointer)?

While answer with reflection is working but it has performance penalties and is not idiomatic to Go.
I believe you should use interface. Like this
https://play.golang.org/p/OG1MPHjDlQ
package main
import (
"fmt"
)
type MySmall interface {
SmallVal() int
}
type Small struct {
val int
}
func (v Small) SmallVal() int {
return v.val
}
type Big struct {
Small
bigval int
}
func main() {
var v interface{} = Big{Small{val: 3}, 4}
fmt.Printf("Small val: %v", v.(MySmall).SmallVal())
}
Output:
Small val: 3

Avoid using unsafe whenever possible. The above task can be done using reflection (reflect package):
var v interface{} = Big{Small{1}, 2}
rf := reflect.ValueOf(v)
s := rf.FieldByName("Small").Interface()
fmt.Printf("%#v\n", s)
fmt.Printf("%#v\n", s.(Small).val)
Output (try it on the Go Playground):
main.Small{val:1}
1
Notes:
This works for any field, not just the first one (at "offset 0"). This also works for named fields too, not just for embedded fields. This doesn't work for unexported fields though.

type Small struct {
val int
}
type Big struct {
Small
bigval int
}
func main() {
var v = Big{Small{10},200}
print(v.val)
}

Related

How to declare and use a struct field which can store both string and int values?

I've the following struct:
type testCase struct {
input string
isValid bool
}
I want to use this struct in multiple tests and input could be either a string or an intetc.
I can convert the int input to string and convert it back to int while processing, or I can define two different structs e.g. testCaseInt and testCaseStruct which will solve my problem but how do I solve this by converting input to an interface?
I'm new to Go and tried Googling about this but couldn't find maybe because I don't know what to search for.
How to declare and use a variable which can store both string and int values in Go?
You cannot. Go's type system (as of Go 1.17) doesn't provide sum types.
You will have to wait for Go 1.18.
tl;dr the trade-off is between static typing and flexible containers.
Up to Go 1.17 you cannot have a struct field with different static types. The best you can have is interface{}, and then assert the dynamic type upon usage. This effectively allows you to have containers of testCases with either type at run time.
type testCase struct {
input interface{}
isValid bool
}
func main() {
// can initialize container with either type
cases := []testCase{{500, false}, {"foobar", true}}
// must type-assert when using
n := cases[0].(int)
s := cases[1].(string)
}
With Go 1.18, you can slightly improve on type safety, in exchange for less flexibility.
Parametrize the struct with a union. This statically restricts the allowed types, but the struct now must be instantiated explicitly, so you can't have containers with different instantiations. This may or may not be compatible with your goals.
type testCase[T int | string] struct {
input T
isValid bool
}
func main() {
// must instantiate with a concrete type
cases := []testCase[int]{
{500, false}, // ok, field takes int value
/*{"foobar", true}*/, // not ok, "foobar" not assignable to int
}
// cases is a slice of testCase with int fields
}
No, instantiating as testCase[any] is a red herring. First of all, any just doesn't satisfy the constraint int | string; even if you relax that, it's actually worse than the Go 1.17 solution, because now instead of using just testCase in function arguments, you must use exactly testCase[any].
Parametrize the struct with a union but still use interface{}/any as field type: (How) can I implement a generic `Either` type in go? . This also doesn't allow to have containers with both types.
In general, if your goal is to have flexible container types (slices, maps, chans) with either type, you have to keep the field as interface{}/any and assert on usage. If you just want to reuse code with static typing at compile-time and you are on Go 1.18, use the union constraint.
Method 1:
package main
import (
"fmt"
)
func main() {
var a interface{}
a = "hi"
if valString, ok := a.(string); ok {
fmt.Printf("String: %s", valString)
}
a = 1
if valInt, ok := a.(int); ok {
fmt.Printf("\nInteger: %d", valInt)
}
}
Method 2:
package main
import (
"fmt"
)
func main() {
print("hi")
print(1)
}
func print(a interface{}) {
switch t := a.(type) {
case int:
fmt.Printf("Integer: %v\n", t)
case string:
fmt.Printf("String: %v\n", t)
}
}
only you can do is this, change string with interface{}
check on play (it works fine)
https://go.dev/play/p/pwSZiZp5oVx
package main
import "fmt"
type testCase struct {
input interface{}
isValid bool
}
func main() {
test1 := testCase{}
test1.input = "STRING". // <-------------------STRING
fmt.Printf("input: %v \n", test1)
test2 := testCase{}
test2.input = 1 // <-------------------INT
fmt.Printf("input: %v \n", test2)
}

Do map of pointers is different with common way of using maps

I want to create cache with map. As map doesn't allow reference to its value, so it's not possible to change values in called functions.
After some search, I found, it's possible with creating map of pointer (of struct). It Almost solve problem and can work like variable by reference
But as i found a few using of this method for map. I worry about using it to be safe.
Is anyone has experience of using map of pointer? and is it right way to use it?
package main
import "fmt"
type Cache struct {
name string
counter int
}
func incr(c Cache) {
c.counter += 1
}
func incrp(c *Cache) {
c.counter += 2
}
func main() {
m := make(map[string]Cache)
m["james"] = Cache{name: "James", counter: 10}
c := m["james"]
incr(c)
fmt.Println(c.name, c.counter) // James 10
mp := make(map[string]*Cache)
mp["james"] = &Cache{name: "James", counter: 10}
cp := mp["james"]
incrp(cp)
fmt.Println(cp.name, cp.counter) // James 12
}
edited: My text had some confusing words and sentences, that caused to misunderstanding, so i tried to fixed it
You can accomplish this and still have a map of non-pointers, with a pointer receiver on the struct:
package main
import "fmt"
type Cache struct {
name string
counter int
}
func (c *Cache) incr() { // the '(c *Cache)' is the receiver;
c.counter += 1 // it makes incr() a method, not just a function
}
func main() {
m := make(map[string]Cache)
m["james"] = Cache{name: "James", counter: 10}
c := m["james"]
c.incr()
fmt.Println(c.name, c.counter)
}
Output:
James 11
If receivers and methods are new to you, here is where they are mentioned in the Tour of Go: https://tour.golang.org/methods/1
Note the page about pointer receivers a few steps later in the Tour: https://tour.golang.org/methods/4

struct type as map key [duplicate]

This question already has an answer here:
golang how can I use struct name as map key
(1 answer)
Closed 9 months ago.
We have a following function:
func (h *Handler) Handle(message interface{}) error {
//here there is a switch for different messages
switch m := message.(type) {
}
}
This signature is given and can't be changed. There are around 20 different message types the handler processes.
Now, there are some of these messages (around 4) which need special post-processing. In a different package.
Thus, I am thinking to do this like this:
func (h *Handler) Handle(message interface{}) error {
//here there is a switch for different messages
switch m := message.(type) {
}
//only post-process if original message processing succeeds
postProcessorPkg.Process(message)
}
Now, in the Process function, I want to quickly lookup if the message type is indeed of the ones we need postprocessing for. I don't want to do a switch again here. There are many handlers, in different packages, with varying amount of message types, and it should be generic.
So I was thinking of registering the message type in the postprocessor and then just do a lookup:
func (p *Postprocessor) Register(msgtype interface{}) {
registeredTypes[msgtype] = msgtype
}
and then
func (p *Postprocessor) Process(msgtype interface{}) error {
if ok := registeredTypes[msgtype]; !ok {
return errors.New("Unsupported message type")
}
prop := GetProp(registeredTypes[msgtype])
doSmthWithProp(prop)
}
This will all not work now because I can only "register" instances of the message, not the message type itself, as far as I know. Thus the map would only match a specific instance of a message, not its type, which is what I need.
So I guess this needs redesign. I can completely ditch the registering and the map lookup, but
I can't change the Handle function to a specific type (signature will need to remain message interface{}
I would like to avoid to have to use reflect, just because I will have a hard time defending such a solution with some colleagues.
As there is no possibility to set a type as the map key, I finally decided to implement the following solution, which is based on #Chrono Kitsune 's solution:
type Postprocess interface {
NeedsPostprocess() bool
}
type MsgWithPostProcess struct {}
func (p *MsgWithPostProcess) NeedsPostprocess() bool {
return true
}
type Msg1 struct {
MsgWithPostProcess
//other stuff
}
type Msg2 struct {
MsgWithPostProcess
//other stuff
}
type Msg3 struct {
//no postprocessing needed
}
func (p *Postprocessor) Process(msgtype interface{}) error {
if _, ok := msgtype.(Postprocess); ok {
//do postprocessing
}
}
As of my simple test I did, only Msg1 and Msg2 will be postprocessed, but not Msg3, which is what I wanted.
This question was the first hit I found on Google but the title is somewhat misleading. So I'll leave this here to add some food for thought with the title of the question in mind.
First, the issue with maps is that its key must be a comparable value. This is why for example a slice cannot be used is a map key. A slice is not comparable and is therefore not allowed. You can use an array (fixed sized slice) but not a slice for the same reason.
Second, you have in the reflect.TypeOf(...).String()a way to get a canonical string representation for types. Though it is not unambiguous unless you include the package path, as you can see here.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type X struct{}
func main() {
fmt.Println(reflect.TypeOf(1).String())
fmt.Println(reflect.TypeOf(X{}).String())
fmt.Println(reflect.TypeOf(&X{}).String())
fmt.Println(reflect.TypeOf(s1.Scanner{}).String())
fmt.Println(reflect.TypeOf(s2.Scanner{}).String())
fmt.Println(reflect.TypeOf(s1.Scanner{}).PkgPath(), reflect.TypeOf(s1.Scanner{}).String())
fmt.Println(reflect.TypeOf(s2.Scanner{}).PkgPath(), reflect.TypeOf(s2.Scanner{}).String())
}
int
main.X
*main.X
scanner.Scanner
scanner.Scanner
text/scanner scanner.Scanner
go/scanner scanner.Scanner
https://play.golang.org/p/NLODZNdik6r
With this information, you can (if you feel so inclined) create a map which let's go from a reflect.Type to a key and back again, like this.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type TypeMap struct {
m []reflect.Type
}
func (m *TypeMap) Get(t reflect.Type) int {
for i, x := range m.m {
if x == t {
return i
}
}
m.m = append(m.m, t)
return len(m.m) - 1
}
func (m *TypeMap) Reverse(t int) reflect.Type {
return m.m[t]
}
type X struct{}
func main() {
var m TypeMap
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(X{})))
fmt.Println(m.Reverse(1))
fmt.Println(m.Get(reflect.TypeOf(&X{})))
fmt.Println(m.Reverse(2))
fmt.Println(m.Get(reflect.TypeOf(s1.Scanner{})))
fmt.Println(m.Reverse(3).PkgPath(), m.Reverse(3))
fmt.Println(m.Get(reflect.TypeOf(s2.Scanner{})))
fmt.Println(m.Reverse(4).PkgPath(), m.Reverse(4))
}
0
int
0
int
0
int
1
main.X
2
*main.X
3
text/scanner scanner.Scanner
4
go/scanner scanner.Scanner
In the above case I'm assuming that N is small. Also note the use of the identity of reflect.TypeOf, it will return the same pointer for the same type on subsequent calls.
If N is not small, you may want to do something a bit more complex.
package main
import (
"fmt"
s2 "go/scanner"
"reflect"
s1 "text/scanner"
)
type PkgPathNum struct {
PkgPath string
Num int
}
type TypeMap struct {
m map[string][]PkgPathNum
r []reflect.Type
}
func (m *TypeMap) Get(t reflect.Type) int {
k := t.String()
xs := m.m[k]
pkgPath := t.PkgPath()
for _, x := range xs {
if x.PkgPath == pkgPath {
return x.Num
}
}
n := len(m.r)
m.r = append(m.r, t)
xs = append(xs, PkgPathNum{pkgPath, n})
if m.m == nil {
m.m = make(map[string][]PkgPathNum)
}
m.m[k] = xs
return n
}
func (m *TypeMap) Reverse(t int) reflect.Type {
return m.r[t]
}
type X struct{}
func main() {
var m TypeMap
fmt.Println(m.Get(reflect.TypeOf(1)))
fmt.Println(m.Reverse(0))
fmt.Println(m.Get(reflect.TypeOf(X{})))
fmt.Println(m.Reverse(1))
fmt.Println(m.Get(reflect.TypeOf(&X{})))
fmt.Println(m.Reverse(2))
fmt.Println(m.Get(reflect.TypeOf(s1.Scanner{})))
fmt.Println(m.Reverse(3).PkgPath(), m.Reverse(3))
fmt.Println(m.Get(reflect.TypeOf(s2.Scanner{})))
fmt.Println(m.Reverse(4).PkgPath(), m.Reverse(4))
}
0
int
1
main.X
2
*main.X
3
text/scanner scanner.Scanner
4
go/scanner scanner.Scanner
https://play.golang.org/p/2fiMZ8qCQtY
Note the subtitles of pointer to type, that, X and *X actually are different types.

generic function to get size of any structure in Go

I am writing a generic function to get the size of any type of structure, similar to sizeof function in C.
I am trying to do this using interfaces and reflection but I'm not able to get the correct result. Code is below:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
getSize(info)
}
func getSize(T interface{}) {
v := reflect.ValueOf(T)
const size = unsafe.Sizeof(v)
fmt.Println(size)
}
This code returns wrong result as 12. I am very new to Go, kindly help me on this.
You're getting the size of the reflect.Value struct, not of the object contained in the interface T. Fortunately, reflect.Type has a Size() method:
size := reflect.TypeOf(T).Size()
This gives me 40, which makes sense because of padding.
Go 1.18
With Go 1.18 you can use a generic function with unsafe.Sizeof:
func getSize[T any]() uintptr {
var v T
return unsafe.Sizeof(v)
}
Note that this will be more performant than using reflect, but it will introduce unsafe in your code base — some static analysis tools may give warnings about that.
However if your goal is to improve code reuse or get sizes at run time (read on for the solution to that), this won't help much because you still need to call the function with proper instantiation:
type myType struct {
a int
b int64
c float32
d float64
e float64
}
func main() {
fmt.Println(getSize[myType]())
}
You might get the most out of this when used as part of some other generic code, e.g. a generic type or function where you pass a type param into getSize. Although if you have the argument v this is equivalent to calling unsafe.Sizeof(v) directly. Using a function could be still useful to hide usage of unsafe. A trivial example:
func printSize[T any](v T) {
// (doing something with v)
// instantiate with T and call
s := getSize[T]()
// s := unsafe.Sizeof(v)
fmt.Println(s)
}
Otherwise you can pass an actual argument to getSize. Then type inference will make it unnecessary to specify the type param. This code perhaps is more flexible and allows you to pass arbitrary arguments at runtime, while keeping the benefits of avoiding reflection:
func getSize[T any](v T) uintptr {
return unsafe.Sizeof(v)
}
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
// inferred type params
fmt.Println(getSize(info)) // 40
fmt.Println(getSize(5.0)) // 8
fmt.Println(getSize([]string{})) // 24
fmt.Println(getSize(struct {
id uint64
s *string
}{})) // 16
}
Playground: https://go.dev/play/p/kfhqYHUwB2S

What's the difference between new(Struct) and &Struct{} in Go?

They seem to be the same:
package main
import "fmt"
type S struct {
i int
}
func main() {
var s1 *S = new(S)
fmt.Println(s1)
var s2 *S = &S{}
fmt.Println(s2) // Prints the same thing.
}
Update:
Hm. I just realized that there's no obvious way to initialize S.i using new. Is there a way to do that? new(S{i:1}) does not seem to work :/
From Effective Go:
As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. The expressions new(File) and &File{} are equivalent.
Not only do they give the same resulting value, but if we allocate something both ways and look at their values...
// Adapted from http://tour.golang.org/#30
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main() {
v := &Vertex{}
v2 := new(Vertex)
fmt.Printf("%p %p", v, v2)
}
...we'll see that they are in fact allocated in consecutive memory slots. Typical output: 0x10328100 0x10328108. I'm not sure if this is an implementation detail or part of the specification, but it does demonstrate that they're both being allocated from the same pool.
Play around with the code here.
As for initializing with new, according to the language spec: The built-in function new takes a type T and returns a value of type *T. The memory [pointed to] is initialized as described in the section on initial values. Because functions in go can't be overloaded, and this isn't a variadic function, there's no way to pass in any initialization data. Instead, go will initialize it with whatever version of 0 makes sense for the type and any member fields, as appropriate.
Case 1: package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := new(Drink)
a.Name = "Maaza"
a.Flavour = "Mango"
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Frooti"
fmt.Println(a.Name)
}//This will output Frooti for a.Name, even though the addresses for a and b are different.
Case 2:
package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := Drink{
Name: "Maaza",
Flavour: "Mango",
}
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Froti"
fmt.Println(a.Name)
}//This will output Maaza for a.Name. To get Frooti in this case assign b:=&a.

Resources