Reputation: 118480
I wish to implement the fmt.Stringer
interface's String
method. However for a set of types deriving from Node
, their String
implementations would be a wrapper around a Print
interface method they must provide. How can I provide String
automatically for all types implementing Node
? If I provide the default String
on some base class, I lose access to the derived type (and thus the interface method Print
).
type Node interface {
fmt.Stringer
Print(NodePrinter)
}
type NodeBase struct{}
func (NodeBase) String() string {
np := NewNodePrinter()
// somehow call derived type passing the NodePrinter
return np.Contents()
}
type NodeChild struct {
NodeBase
// other stuff
}
func (NodeChild) Print(NodePrinter) {
// code that prints self to node printer
}
Upvotes: 2
Views: 124
Reputation: 3914
If you want it more flexible for future changes, i.e. if your node object need different code to print themselves and you have some common printing code, that you want to have pluggable, consider this:
package main
type printableNode struct{
// define whatever a printer needs to be able to print a node
}
type Node interface {
// or return some other type that can be handled by NodePrinter
Printable() printableNode
}
type NodeBase struct{}
// printable representation of a nodebase
func (nb NodeBase) Printable() printableNode {
}
type NodeChild struct {
NodeBase
// other stuff
}
// may make use of nc.Nodebase.Printable()
func (nc NodeChild) Printable() printableNode {
}
type Print struct{Node}
// do the common stuff, in other places you may define other printers
// this way
func (pr Print) String() string {
// do something with pr.Node.Printable() and return a string
}
// you may also use a simple function that receives a node and returns a string
func Print2(n Node) string {
// do something with n.Printable() and return a string
}
func main() {
nb := Nodebase{}
// use it to print
fmt.Println(Print{nb})
// or (simpler)
fmt.Println(Print2(nb))
}
Upvotes: 0
Reputation:
In the Go language there is no support for getting to the containing object (NodeChild
) of an object (NodeBase
). But you can implement this functionality yourself:
type Node interface {
fmt.Stringer
Print(NodePrinter)
}
type NodeBase struct {
Self Node
}
func (n NodeBase) String() string {
np := NewNodePrinter()
n.Self.Print(np)
return np.Contents()
}
type NodeChild struct {
NodeBase
// other stuff
}
func NewNodeChild() *NodeChild {
var n NodeChild
n.Self = &n
return &n
}
func (*NodeChild) Print(NodePrinter) {
// code that prints self to node printer
}
More generally:
type Object struct {
Self interface{}
}
type NodeBase struct {
Object
}
...
Upvotes: 0
Reputation: 28086
Go explicitly declares that it's not possible:
When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one.
For a solution, I recommend something like this:
func nodeString(n Node) string {
np := NewNodePrinter()
// do stuff
n.Print(np)
return np.Contents()
}
// Now you can add String method to any Node in one line
func (n NodeChild) String() string { return nodeString(n) }
Upvotes: 2