How to convert a struct to a different struct with fewer fields - go

I am trying to copy a struct of type Big to type Small without explicitly creating a new struct of type Small with the same fields.
I have tried searching for other similar problems such as this and this yet all the conversions between different struct types happen only if the structs have the same fields.
Here is an example of what I tried to do:
// Big has all the fields that Small has including some new ones.
type Big struct {
A int
B string
C float
D byte
}
type Small struct {
A int
B string
}
// This is the current solution which I hope to not use.
func ConvertFromBigToSmall(big Big) Small {
return Small{
A: big.A,
B: big.B,
}
}
I expected to be able to do something like this, yet it does not work:
big := Big{}
small := Small(big)
Is there a way of converting between Big to Small (and maybe even vice-versa) without using a Convert function?

There is no built-in support for this. If you really need this, you could write a general function which uses reflection to copy the fields.
Or you could redesign. If Big is a Small plus some other, additional fields, why not reuse Small in Big?
type Small struct {
A int
B string
}
type Big struct {
S Small
C float
D byte
}
Then if you have a Big struct, you also have a Small: Big.S. If you have a Small and you need a Big: Big{S: small}.
If you worry about losing the convenience of shorter field names, or different marshalled results, then use embedding instead of a named field:
type Big struct {
Small // Embedding
C float
D byte
}
Then these are also valid: Big.A, Big.B. But if you need a Small value, you can refer to the embedded field using the unqualified type name as the field name, e.g. Big.Small (see Golang embedded struct type). Similarly, to create a Big from a Small: Big{Small: small}.

Is there a way of converting between Big to Small (and maybe even vice-versa) without using a Convert function?
The only option is to do it manually, as you have done. Whether you wrap that in a function or not, is a matter of taste/circumstance.

you can do something like this:
package main
import (
"fmt"
)
type Big struct {
Small
C float32
D byte
}
type Small struct {
A int
B string
}
func main() {
big := new(Big)
big.A = 1
big.B = "test"
big.C = 2.3
fmt.Printf("big struct: %+v", big)
fmt.Println()
small := big.Small
fmt.Printf("small struct: %+v", small)
fmt.Println()
}
output:
big struct: &{Small:{A:1 B:test} C:2.3 D:0}
small struct: {A:1 B:test}
playgroundlink:https://play.golang.org/p/-jP8Wb--att

I'm afraid there is no direct way to do that. What you did is the right way.
You can try to write the first object to JSON and then try to parse it back to the second object. Though, I wouldn't go this way.
One more way, which is a specific one is that the Big object will inherit the Small object. then you can downcast. Again, I wouldn't do that but if you must...

Related

Can I get a variable of a type based on reflect.Type [duplicate]

I have a function which takes an interface, like this:
func method(data interface{})
.. because I need to process different structs which have common fields/methods. In this function I use data tens or hundreds of times, in different places. It's really unpleasant to add switch a.(type) { case .. case .. all the time.
Is there a way to create a variable with just one switch with needed type and then just use this variable everywhere later? Something like:
var a .... // something here
switch data.(type) {
case *Struct1:
a = data.(*Struct1)
case *Struct2:
a = data.(*Struct2)
}
// Continue with 'a' only
a.Param = 15
fmt.Println(a.String())
Go is a statically typed language, the type of a must be known at compile time. And since Go does not support generics yet, you can't do what you want.
Try to come up with some other solution, e.g. abstract away the things you want to do with a into an interface, and have the concrete types implement that interface. Then a can be a variable of this interface type, and you can call methods of it.
If you can achieve this, actually you can even change the parameter of the data type to this interface, and no type assertion or type switch is needed.
Alternatively you could use reflection to access common fields (either for get or set) identified by their name, but reflection provides no compile-time guarantee, and it's usually less efficient. For an example how to do that, see this question: Assert interface to its type
You can't do what you ask for in your question directly, go is statically typed, so you can't have one variable that can hold different types, and still access that variable as if it is typed.
If you're only working on the common struct fields in your method, you are perhaps better off gathering all the common variables in its own struct, illustrated below as the commons struct and have your method take that type as an argument
package main
import (
"fmt"
)
type commons struct {
name string
age int
}
type structA struct {
commons
other_stuff int
}
type structB struct {
commons
foo string
}
func method(c* commons) {
fmt.Println(c)
c.age +=1
}
func main() {
a := structA{commons{"foo", 44}, 1}
b := structB{commons{"bar", 33}, "test"}
method(&a.commons)
method(&b.commons)
fmt.Println(a)
}
Go playground
I can't figure out what is your real goal but if the "method" you want to write handles common fields from similar structures, and you cannot fix original structures using Type Embedding, as #nos said above, then you can try to make another structure for method-internal use:
var v Vehicle // with common fields
switch data.(type) {
case *Car:
v.Handle = data.(*Car).Handle // or CircleHandle
case *Motorcycle:
v.Handle = data.(*Motorcycle).Handle // or BarHandle
}
v.Degree = 15
v.Speed = 50
v.Direction = "left"
v.Style = "rough"
/// so many things on `v`...
steering(v)
I think it is not a good approach but sometimes... :-)

Typecasting structs with same underlying types

For basic types we can easily cast the types if their underlying types are same .But the fields inside struct with same memory layout cannot be easily cast from one to another type.
There is a proposal for this problem unfortunately it got rejected .After an hour of googling with no luck I came here seeking the help from experts.
Look at example below
:
package main
import (
"fmt"
)
type Int int
type A struct {
name string
age Int
}
type B struct {
name string
age int
}
func main() {
var a A= A{"Foo",21}
var b B= B{"Bar", 21}
fmt.Println(a,b,(A)(b)) //Error here as expected
}
Eventhough struct A and B has the same underlying type of struct { string,int} why cannot I cast to each other as the underlying type of Int is int.
Whether it is possible to cast recursively unless the underlying type differs?
You can't do it simply because the language spec does not allow it. Regarding structs, you can only convert from one type to the other if Spec: Conversion:
A non-constant value x can be converted to type T in any of these cases:
...
ignoring struct tags (see below), x's type and T have identical underlying types.
If you're absolutely sure the structs' memory layout is identical, you may use an unsafe conversion (using package unsafe) like this:
var a A = A{"Foo", 21}
var b B
b = *(*B)(unsafe.Pointer(&a))
fmt.Println(a, b)
This will output (try it on the Go Playground):
{Foo 21} {Foo 21}
But use this as the last resort. Using unsafe you lose compile time type safety and portability guarantees. E.g. if later you only modify one of the structs, the above code will continue to compile even though it might not be correct anymore, and the compiler will not able to inform you about that.

Is type casting structs in Go a no-op?

Consider the following code in Go
type A struct {
f int
}
type B struct {
f int `somepkg:"somevalue"`
}
func f() {
var b *B = (*B)(&A{1}) // <-- THIS
fmt.Printf("%#v\n", b)
}
Will the marked line result in a memory copy (which I would like to avoid as A has many fields attached to it) or will it be just a reinterpretation, similar to casting an int to an uint?
EDIT: I was concerned, whether the whole struct would have to be copied, similarly to converting a byte slice to a string. A pointer copy is therefore a no-op for me
It is called a conversion. The expression (&A{}) creates a pointer to an instance of type A, and (*B) converts that pointer to a *B. What's copied there is the pointer, not the struct. You can validate this using the following code:
a:=A{}
var b *B = (*B)(&a)
b.f=2
fmt.Printf("%#v\n", a)
Prints 2.
The crucial points to understand is that
First, unlike C, C++ and some other languages of their ilk, Go does not have type casting, it has type conversions.
In most, but not all, cases, type conversion changes the type but not the internal representation of a value.
Second, as to whether a type conversion "is a no-op", depends on how you define the fact of being a no-op.
If you are concerned with a memory copy being made, there are two cases:
Some type conversions are defined to drastically change the value's representation or to copy memory; for example:
Type-converting a value of type string to []rune would interpret the value as a UTF-8-encoded byte stream, decode each encoded Unicode code point and produce a freshly-allocated slice of decoded Unicode runes.
Type-converting a value of type string to []byte, and vice-versa, will clone the backing array underlying the value.
Other type-conversions are no-op in this sense but in order for them to be useful you'd need to either assign a type-converted value to some variable or to pass it as an argument to a function call or send to a channel etc — in other words, you have to store the result or otherwise make use of it.
All of such operations do copy the value, even though it does not "look" like this; consider:
package main
import (
"fmt"
)
type A struct {
X int
}
type B struct {
X int
}
func (b B) Whatever() {
fmt.Println(b.X)
}
func main() {
a := A{X: 42}
B(a).Whatever()
b := B(a)
b.Whatever()
}
Here, the first type conversion in main does not look like a memory copy, but the resulting value will serve as a receiver in the call to B.Whatever and will be physically copied there.
The second type conversion stores the result in a variable (and then copies it again when a method is called).
Reasonong about such things is easy in Go as there everything, always, is passed by value (and pointers are values, too).
It may worth adding that variables in Go does not store the type of the value they hold, so a type conversion cannot mutate the type of a variable "in place". Values do not have type information stored in them, either. This basically means that type conversions is what compiler is concerned with: it knows the types of all the participating values and variables and performs type checking.

map[T]struct{} and map[T]bool in golang

What's the difference? Is map[T]bool optimized to map[T]struct{}? Which is the best practice in Go?
Perhaps the best reason to use map[T]struct{} is that you don't have to answer the question "what does it mean if the value is false"?
From "The Go Programming Language":
The struct type with no fields is called the empty struct, written
struct{}. It has size zero and carries no information but may be
useful nonetheless. Some Go programmers use it instead of bool as the
value type of a map that represents a set, to emphasize that only the
keys are significant, but the space saving is marginal and the syntax
more cumbersome, so we generally avoid it.
If you use bool testing for presence in the "set" is slightly nicer since you can just say:
if mySet["something"] {
/* .. */
}
Difference is in memory requirements. Under the bonnet empty struct is not a pointer but a special value to save memory.
An empty struct is a struct type like any other. All the properties you are used to with normal structs apply equally to the empty struct. You can declare an array of structs{}s, but they of course consume no storage.
var x [100]struct{}
fmt.Println(unsafe.Sizeof(x)) // prints 0
If empty structs hold no data, it is not possible to determine if two struct{} values are different.
Considering the above statements it means that we may use them as method receivers.
type S struct{}
func (s *S) addr() { fmt.Printf("%p\n", s) }
func main() {
var a, b S
a.addr() // 0x1beeb0
b.addr() // 0x1beeb0
}

Why create go types based on other?

what is the purpose of defining new types in go:
type NewType OldType
since NewType have only methods declarations, so:
var x NewType
can store also OldType 'objects'. Are there any advantages?
The reason behind naming types in general is fairly straightforward, and is much the same in most languages - being able to name complex types, like:
type Person struct{
name String
age uint8
}
However, naming a type like you described, which I'll call "type aliasing" (not sure if this is used by anyone else, but it's the term I tend to use), doesn't give you the above-mentioned advantage. What it does give you, however, is the ability to add methods to existing types. Go disallows you from adding methods to existing types that you did not define yourself (ie, built-in types or types defined in other packages), so aliasing allows you to pretend that you did define them yourself, and thus add methods to them. Another good way to think about it is like a much more concise version of creating a wrapper type (as you would in an OO language like Java, for example).
So, let's say that I wanted to be able use integers as errors. In Go, the error interface simply requires a method called "Error" which returns a string. Using type aliasing, I could do:
type errorCode int
func (e errorCode) Error() string {
return fmt.Sprintf("%d", e)
}
...and I could use integer error codes. By contrast, if I tried the following, I would get an error:
func (e int) Error() string {
return fmt.Sprintf("%d", e)
}
To demonstrate, check out this implementation:
http://play.golang.org/p/9NO6Lcdsbq
Just to clarify (because my use of the word "alias" may be misleading), two types which are otherwise equivalent (for example, int and errorCode in the above example) are not interchangeable. The Go type system treats them as fundamentally different types, although you may be able to type-cast between them.
The Go Programming Language Specification
Types
A type determines the set of values and operations specific to values
of that type.
You want identify a specific set of values and operations.
For example,
package main
import "fmt"
type Coordinate float64
type Point struct {
x, y Coordinate
}
func (p *Point) Move(dx, dy Coordinate) {
p.x += dx
p.y += dy
}
func main() {
var p = Point{3.14159, 2.718}
fmt.Println(p)
p.Move(-1, +1)
fmt.Println(p)
}
Output:
{3.14159 2.718}
{2.14159 3.718}

Resources