Reputation: 25
Below is simplified Go code.
As you can see, it wrote twice String()
, is there any way to write just once?
type A struct {
Name string
}
func (u A) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("A:\n" + string(out))
}
type B struct {
Name string
}
func (u B) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("B:\n" + string(out))
}
Something like to implement a struct Base
, which has a method did()
,
then struct A
and struct B
implement struct Base
, so they can call did()
without need to implement did()
itself again.
==============
Edited:
The previous sample code is not very clear, now I changed it.
The struct A
and struct B
have different fields, and how can we write String()
just once, then apply to two structs?
type A struct {
Name string
Status string
}
func (u A) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("A:\n" + string(out))
}
type B struct {
ID int
Logo string
}
func (u B) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("B:\n" + string(out))
}
Upvotes: 1
Views: 1030
Reputation: 79516
Is there any way to write just once?
TL;DR Probably not.
In your exact example, there are two approaches that will work, but neither is very useful in real code, and I expect neither will address your actual need.
The most obvious is to have just a single type, since they're identical anyway. Or make your second type a copy of the first:
type A struct {
Name string
}
func (u A) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("A:\n" + string(out))
}
type B A
You can use struct embedding. This works because your structs contain exactly the same fields, so they can both embed a common struct:
type common struct {
Name string
}
func (u common) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("A:\n" + string(out))
}
type A struct {
common
}
type B struct {
common
}
However, I expect your two structs also contain more fields that are not shared. Which means that both of these approaches won't work. As in example 2, you can embed a struct with the common values, but then your String()
method will only have access to the common fields. See an example in the playground
A final approach, which might apply to you, but absolutely will not apply in all cases, is to write a custom String()
method on each of the outer types, which in turn calls an embedded String()
function to calculate the common part. Whether this works for you or not, of course, depends a lot on what format you want. I discuss a similar approach for JSON marshaling with embedded structs on my blog, and in this SO answer. Since your String()
method is actually producing JSON, it may apply to you, as well.
It might look something like this:
type common struct {
Name string
}
func (u common) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf("A:\n" + string(out))
}
type A struct {
common
Age int
}
func (u A) String() string {
return fmt.Sprintf("%s Age: %d", u.common.String(), u.Age)
}
Upvotes: 1
Reputation: 1530
Yes, there is a way to do this in Go. But it may or may not work depending on your exact use case. You can use an embedded struct.
That would look like this:
type Stringer struct {
Name string
}
func (u Stringer) String() string {
out, err := json.MarshalIndent(u, "", "\t")
return fmt.Sprintf(string(out))
}
type A struct {
Stringer
}
type B struct {
Stringer
}
Note that any fields which are in A
or B
but not in Stringer will not be included in the result of String() string
. Thus this may not work for your case if you require any such fields.
Upvotes: 0
Reputation: 825
You can use a embedded struct like so which implements the String
method
package main
import (
"encoding/json"
"fmt"
)
type A struct {
embd
}
type B struct {
embd
}
type embd struct {
Name string
typ string
}
func (e embd) String() string {
out, err := json.MarshalIndent(e, "", "\t")
if err != nil {
panic(err)
}
return fmt.Sprintf(e.typ + ":\n" + string(out))
}
func main() {
a := A{embd{"Foo", "A"}}
fmt.Println(a.String())
b := B{embd{"Bar", "B"}}
fmt.Println(b.String())
}
Upvotes: 0