chellathurai
chellathurai

Reputation: 115

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?

Upvotes: 0

Views: 2273

Answers (2)

 Bruno
 Bruno

Reputation: 21

The reason why this conversion isn't allowed in your program:

type A B   // this isn't a type alias

In this example A has the same binary structure as B. However A doesn't inherit any methods associated with B at all!

Let's assume this code:

func (b B) method()

The following would be valid

var b B
b.method()

This is INVALID

var a A
a.method() // for type A no method of name 'method' exists

The Spec assumes that A and B could be indeed very different. So no type conversion allowed.

You could use instead a type alias like that:

type Int = int

Here is a Playground link.

Upvotes: 1

icza
icza

Reputation: 417622

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:

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.

Upvotes: 2

Related Questions