Golang中如何为不同结构体使用相同的方法

Golang中如何为不同结构体使用相同的方法 我有两个结构体,它们都拥有相同的方法:

func (r *myStruct1) DoThis() error {}
func (r *myStruct1) DoThat() error {}

func (r *myStruct2) DoThis() error {}
func (r *myStruct2) DoThat() error {}

我不喜欢这里的重复代码,因为它们实际上做的是同一件事,只是针对不同的结构体。有没有什么方法可以将其通用化?如果可以,能否提供一个代码示例?

2 回复

这被称为组合设计模式。

package main

import "fmt"

type myStruct1 struct {
	method func()
}

type myStruct2 struct {
	method func()
}

func doThis() {
	fmt.Println("test")
}

func main() {

	struct1 := myStruct1{
		method: doThis,
	}

	struct2 := myStruct1{
		method: doThis,
	}

	struct1.method()
	struct2.method()
}

更多关于Golang中如何为不同结构体使用相同的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中可以通过接口和嵌入两种方式实现不同结构体共享相同方法。以下是具体实现:

方法1:使用接口定义通用行为

package main

import "fmt"

// 定义接口
type Doer interface {
    DoThis() error
    DoThat() error
}

// 结构体1
type myStruct1 struct {
    Name string
}

// 结构体2
type myStruct2 struct {
    ID int
}

// 通用实现函数
func commonDoThis(d Doer) error {
    // 这里可以根据需要访问具体结构体的字段
    fmt.Println("DoThis executed")
    return nil
}

func commonDoThat(d Doer) error {
    fmt.Println("DoThat executed")
    return nil
}

// 为myStruct1实现接口
func (r *myStruct1) DoThis() error {
    return commonDoThis(r)
}

func (r *myStruct1) DoThat() error {
    return commonDoThat(r)
}

// 为myStruct2实现接口
func (r *myStruct2) DoThis() error {
    return commonDoThis(r)
}

func (r *myStruct2) DoThat() error {
    return commonDoThat(r)
}

func main() {
    s1 := &myStruct1{Name: "test1"}
    s2 := &myStruct2{ID: 123}
    
    s1.DoThis()
    s2.DoThat()
}

方法2:使用嵌入结构体

package main

import "fmt"

// 基础结构体包含通用方法
type BaseActions struct{}

func (b *BaseActions) DoThis() error {
    fmt.Println("Base DoThis")
    return nil
}

func (b *BaseActions) DoThat() error {
    fmt.Println("Base DoThat")
    return nil
}

// 结构体1嵌入BaseActions
type myStruct1 struct {
    BaseActions
    Name string
}

// 结构体2嵌入BaseActions
type myStruct2 struct {
    BaseActions
    ID int
}

// 如果需要覆盖方法
func (r *myStruct1) DoThis() error {
    fmt.Printf("myStruct1 DoThis with Name: %s\n", r.Name)
    return nil
}

func main() {
    s1 := &myStruct1{Name: "struct1"}
    s2 := &myStruct2{ID: 100}
    
    s1.DoThis() // 使用覆盖的方法
    s1.DoThat() // 使用嵌入的方法
    s2.DoThis() // 使用嵌入的方法
    s2.DoThat() // 使用嵌入的方法
}

方法3:使用函数组合

package main

import "fmt"

// 结构体定义
type myStruct1 struct {
    Value string
}

type myStruct2 struct {
    Value int
}

// 通用函数
func DoThisGeneric[T any](obj *T, getValue func(*T) string) error {
    value := getValue(obj)
    fmt.Printf("DoThis with value: %s\n", value)
    return nil
}

func DoThatGeneric[T any](obj *T, getValue func(*T) string) error {
    value := getValue(obj)
    fmt.Printf("DoThat with value: %s\n", value)
    return nil
}

// 具体结构体的方法
func (r *myStruct1) DoThis() error {
    return DoThisGeneric(r, func(m *myStruct1) string {
        return m.Value
    })
}

func (r *myStruct1) DoThat() error {
    return DoThatGeneric(r, func(m *myStruct1) string {
        return m.Value
    })
}

func (r *myStruct2) DoThis() error {
    return DoThisGeneric(r, func(m *myStruct2) string {
        return fmt.Sprintf("%d", m.Value)
    })
}

func (r *myStruct2) DoThat() error {
    return DoThatGeneric(r, func(m *myStruct2) string {
        return fmt.Sprintf("%d", m.Value)
    })
}

func main() {
    s1 := &myStruct1{Value: "hello"}
    s2 := &myStruct2{Value: 42}
    
    s1.DoThis()
    s2.DoThat()
}

方法4:Go 1.18+ 使用泛型

package main

import "fmt"

// 定义通用接口
type Doer interface {
    DoThis() error
    DoThat() error
}

// 通用结构体包装器
type GenericStruct[T any] struct {
    Data   T
    doThis func(*T) error
    doThat func(*T) error
}

func (g *GenericStruct[T]) DoThis() error {
    return g.doThis(&g.Data)
}

func (g *GenericStruct[T]) DoThat() error {
    return g.doThat(&g.Data)
}

// 创建具体实例的辅助函数
func NewMyStruct1(name string) Doer {
    return &GenericStruct[myStruct1]{
        Data: myStruct1{Name: name},
        doThis: func(m *myStruct1) error {
            fmt.Printf("myStruct1 DoThis: %s\n", m.Name)
            return nil
        },
        doThat: func(m *myStruct1) error {
            fmt.Printf("myStruct1 DoThat: %s\n", m.Name)
            return nil
        },
    }
}

func NewMyStruct2(id int) Doer {
    return &GenericStruct[myStruct2]{
        Data: myStruct2{ID: id},
        doThis: func(m *myStruct2) error {
            fmt.Printf("myStruct2 DoThis: %d\n", m.ID)
            return nil
        },
        doThat: func(m *myStruct2) error {
            fmt.Printf("myStruct2 DoThat: %d\n", m.ID)
            return nil
        },
    }
}

type myStruct1 struct {
    Name string
}

type myStruct2 struct {
    ID int
}

func main() {
    s1 := NewMyStruct1("test")
    s2 := NewMyStruct2(123)
    
    s1.DoThis()
    s1.DoThat()
    s2.DoThis()
    s2.DoThat()
}

嵌入结构体是最简洁的方式,接口方式更符合Go的惯用法,泛型方式在Go 1.18+中提供了更强的类型安全性。选择哪种方式取决于具体需求和Go版本。

回到顶部