【问题标题】:different structs reusing same method不同的结构重用相同的方法
【发布时间】:2020-07-08 07:20:06
【问题描述】:

以下是简化的 Go 代码。

如你所见,它写了两次String(),有什么办法只写一次吗?

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

类似于实现struct Base,它有一个方法did()

然后struct Astruct B 实现struct Base,因此他们可以调用did() 而无需再次实现did() 本身。

==============

已编辑:

之前的示例代码不是很清楚,现在改了。

struct Astruct B 有不同的字段,我们如何只写一次String(),然后应用于两个结构?

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

【问题讨论】:

    标签: go inheritance struct embedding


    【解决方案1】:

    有没有办法只写一次?

    TL;DR可能不会。

    在您的确切示例中,有两种方法可行,但在实际代码中都不是很有用,我希望这两种方法都不能满足您的实际需求。

    1. 最明显的是只有一种类型,因为它们无论如何都是相同的。或者让您的第二种类型成为第一种的副本:

      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
      
    2. 您可以使用结构嵌入。这是可行的,因为您的结构包含完全相同的字段,因此它们都可以嵌入一个通用结构:

      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
      }
      

    但是,我希望您的两个结构还包含更多未共享的字段。这意味着这两种方法都行不通。如示例 2,您可以嵌入具有公共值的结构,但您的 String() 方法将只能访问公共字段。查看示例in the playground

    最后一种方法,可能适用于您,但绝对不适用于所有情况,是在每个外部类型上编写自定义 String() 方法,然后调用嵌入的 String() 函数来计算共同的部分。当然,这是否适合您,很大程度上取决于您想要什么格式。我在on my blogthis SO answer 中讨论了用于JSON 编组的类似方法。由于您的 String() 方法实际上是在生成 JSON,因此它也可能适用于您。

    它可能看起来像这样:

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

    【讨论】:

      【解决方案2】:

      您可以使用像这样实现String 方法的嵌入式结构

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

      【讨论】:

        【解决方案3】:

        是的,在 Go 中有一种方法可以做到这一点。但它可能会或可能不会工作,具体取决于您的确切用例。您可以使用embedded struct

        看起来像这样:

        Go Playground

        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
        }
        

        请注意,AB 中但不在 Stringer 中的任何字段都不会包含在 String() string 的结果中。因此,如果您需要任何此类字段,这可能不适用于您的情况。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-04
          • 1970-01-01
          相关资源
          最近更新 更多