I thought a type alias would be more elegant than embedding a struct. You see, if I create a new type BigInt
that embeds big.Int
, I'd have to take care that the embedded big.Int is initialized at all times, and unless I reimplement big.Int's like Cmp, Add, Sub, all the code that depends on this new type needs to know that BigInt
's methods actually receive a big.Int
for their arguments. Which is stupid.
So I tried aliasing a type.
type BigInt big.Int
// String casts BigInt into big.Int and uses its String method.
func (b *BigInt) String() string {
bc := big.Int(*b)
return bc.String()
}
But Setting the pointer receiver is now very tricky because I don't have access to the internals of big.Int. This following code doesn't work at all:
// UnmarshalJSON casts BigInt into big.Int and uses its UnmarshalJSON method.
func (b *BigInt) UnmarshalJSON(text []byte) error {
bc := new(big.Int)
err := bc.UnmarshalJSON(text)
if err != nil {
return err
}
b = b.Set(bc)
return nil
}
// Set is different from big.Int.Set() in that you must use the value it returns
func (b *BigInt) Set(i *big.Int) *BigInt {
iB := BigInt(*i)
b = &iB
return b
}
What can I do?
That isn't a type alias, it's a new type, and therefor has none of the methods of the underlying big.Int
type. A type alias would be type BigInt = big.Int
, but then you couldn't define new methods on it. A type's methods are locked to its package: there is no way to define methods on an imported type in addition to the methods it already has defined. Embedding is the closest you're likely to get to that. More likely you want to reconsider your design, most likely by creating functions that take a big.Int
instead of trying to define new methods.
I forgot that I can dereference the pointer receiver /left hand side of the =
sign as well. This does exactly what I wanted...
// Set makes a BigInt equal to a given big.Int.
func (b *BigInt) Set(i *big.Int) *BigInt {
iB := BigInt(*i)
*b = iB
return b
}