在另一个形式中实现一个接口

huangapple go评论93阅读模式
英文:

Implement an interface in the form of another

问题

我希望实现fmt.Stringer接口的String方法。然而,对于一组派生自Node的类型,它们的String实现将是一个围绕它们必须提供的Print接口方法的包装器。如何为所有实现Node的类型自动提供String方法?如果我在某个基类上提供默认的String方法,我将失去对派生类型(因此也失去对接口方法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
}
英文:

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
}

答案1

得分: 2

Go 明确声明 这是不可能的:

> 当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但当它们被调用时,方法的接收者是内部类型,而不是外部类型。

对于解决方案,我建议像这样做:

func nodeString(n Node) string {
    np := NewNodePrinter()
    // 做一些操作
    n.Print(np)
    return np.Contents()
}

// 现在你可以在一行中为任何 Node 添加 String 方法
func (n NodeChild) String() string { return nodeString(n) }
英文:

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) }

答案2

得分: 0

在Go语言中,没有支持获取包含对象(NodeBase)的对象(NodeChild)的功能。但是你可以自己实现这个功能:

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
    // 其他内容
}

func NewNodeChild() *NodeChild {
    var n NodeChild
    n.Self = &n
    return &n
}

func (*NodeChild) Print(NodePrinter) {
    // 打印自身到节点打印机的代码
}

更一般地说

type Object struct {
    Self interface{}
}

type NodeBase struct {
    Object
}

...
英文:

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
}

...

答案3

得分: 0

如果您希望将来更灵活地进行更改,即如果您的节点对象需要不同的代码来打印自己,并且您有一些通用的打印代码,您希望能够插入,请考虑以下内容:

package main 

type printableNode struct{
    // 定义打印节点所需的任何内容
}

type Node interface {
    // 或者返回其他可以由NodePrinter处理的类型
    Printable() printableNode
}

type NodeBase struct{}

// 节点基类的可打印表示
func (nb NodeBase) Printable() printableNode {
}

type NodeChild struct {
    NodeBase
    // 其他内容
}

// 可能会使用nc.Nodebase.Printable()
func (nc NodeChild) Printable() printableNode {
}

type Print struct{Node}

// 在其他地方可以定义其他打印机的通用内容
func (pr Print) String() string {
    // 使用pr.Node.Printable()做一些操作,并返回一个字符串
}

// 您还可以使用一个简单的函数,接收一个节点并返回一个字符串
func Print2(n Node) string {
   // 使用n.Printable()做一些操作,并返回一个字符串
}


func main() {
    nb := Nodebase{}
    // 使用它进行打印
    fmt.Println(Print{nb})
    // 或者(更简单)
    fmt.Println(Print2(nb))
}
英文:

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))
}

huangapple
  • 本文由 发表于 2012年5月8日 15:18:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/10494303.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定