Golang中的通用接收器或类似功能探讨

Golang中的通用接收器或类似功能探讨 在一个应用中,我有3个结构体。它们是:

type LoginResponse struct {
    ResultResponse
    Token      string `json:"Token"`
    ComercioId string `json:"ComercioId"`
    UsuarioId  string `json:"UsuarioId"`
}
type DepositoPagoResponse struct {
    ResultResponse
    TransaccionID    int       `json:"TransaccionId"`
    Producto         string    `json:"Producto"`
    FechaTransaccion time.Time `json:"FechaTransaccion"`
    MontoTransaccion float64   `json:"MontoTransaccion"`
}
type VerifyAccountResponse struct {
    ResultResponse
    Producto string  `json:"Producto"`
    Saldo    float64 `json:"Saldo"`
}
type ResultResponse struct {
    IsSuccess bool   `json:"IsSuccess"`
    Codigo    int    `json:"Codigo"`
    Mensaje   string `json:"Mensaje"`
}

为了在我的结构体中设置属性,我编写了一些方法,其工作方式类似于建造者模式。例如:

func (r *VerifyAccountResponse) WithSuccess(success bool) *VerifyAccountResponse {
    r.IsSuccess = success
    return r
}
func (r *VerifyAccountResponse) WithCodigo(codigo int) *VerifyAccountResponse {
    codigo, mensaje := GetCodeMessage(codigo)
    r.Codigo = codigo
    r.Mensaje = mensaje
    return r
}

所以我写了类似这样的代码:

r := &LoginResponse{}
r.WithSuccess(true).WithCode(100).WithToken("123")

等等。WithSuccessWithCode 这些方法在每个结构体中都是重复的。

我希望只为 ResultResponse 编写这些方法一次,然后让每个父结构体都能使用。

我在考虑类似泛型函数接收器之类的东西,以避免为每个父结构体编写这些方法。

这可能吗?如果可以,请提供一些有用的提示……


更多关于Golang中的通用接收器或类似功能探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

这不是一个问题,只是想了解如何处理泛型和接收器。

谢谢!!!

更多关于Golang中的通用接收器或类似功能探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这就是我所做的……非常感谢!!!

这样写有什么问题:

r := LoginResponse{
	ResultResponse: ResultResponse{
		IsSuccess: true,
		Codigo:    100,
	},
	Token: "123",
}

我找到了一个让代码更简洁的方法。首先,我写了一个函数来创建 ResultResponse 对象,然后为其他每个结构体添加一个 WithResultResponse 方法。就像这样:

response.WithResultResponse(models.BuildResultResponse(true, 1097)).
WithToken(“abc123”).
WithUsuarioId(“usuario_1”).
WithComercioId(“9999”)

Go 语言不允许你编写与嵌入式结构体(如 ResultResponse)绑定的泛型构建器方法,因此,如果你想保持链式调用(WithSuccessWithCodigo 等),就必须为每个父类型重复编写这些方法。为了减少重复,你可以将共享的逻辑移到辅助函数中,然后在每个结构体的构建器方法中调用这些辅助函数。这样更清晰,即使没有完全遵循 DRY 原则。除非你深入研究高级模式,否则泛型或接口在这里帮助不大,而引入高级模式可能不值得增加复杂性。

func main() {
    fmt.Println("hello world")
}

在Go中可以通过为嵌入的ResultResponse类型定义方法来实现代码复用。由于你的结构体都嵌入了ResultResponse,可以为ResultResponse定义方法,这些方法会返回*ResultResponse,然后通过类型转换或方法链来使用。

以下是实现方案:

// 为 ResultResponse 定义通用方法
func (r *ResultResponse) WithSuccess(success bool) *ResultResponse {
    r.IsSuccess = success
    return r
}

func (r *ResultResponse) WithCodigo(codigo int) *ResultResponse {
    codigo, mensaje := GetCodeMessage(codigo)
    r.Codigo = codigo
    r.Mensaje = mensaje
    return r
}

// 使用示例
func main() {
    // 方法1:直接操作嵌入的ResultResponse
    loginResp := &LoginResponse{}
    loginResp.ResultResponse.WithSuccess(true).WithCodigo(100)
    loginResp.Token = "123"
    
    // 方法2:创建辅助函数来链式调用
    depositResp := &DepositoPagoResponse{}
    depositResp.WithResult(true, 100).Producto = "Producto1"
}

// 辅助函数示例
func (r *LoginResponse) WithResult(success bool, codigo int) *LoginResponse {
    r.ResultResponse.WithSuccess(success).WithCodigo(codigo)
    return r
}

func (r *DepositoPagoResponse) WithResult(success bool, codigo int) *DepositoPagoResponse {
    r.ResultResponse.WithSuccess(success).WithCodigo(codigo)
    return r
}

如果需要保持完全相同的链式调用语法,可以使用接口和类型断言:

type ResultBuilder interface {
    WithSuccess(bool) ResultBuilder
    WithCodigo(int) ResultBuilder
}

// 确保所有响应类型都实现ResultBuilder
var _ ResultBuilder = (*LoginResponse)(nil)
var _ ResultBuilder = (*DepositoPagoResponse)(nil)

func (r *LoginResponse) WithSuccess(success bool) ResultBuilder {
    r.ResultResponse.WithSuccess(success)
    return r
}

func (r *LoginResponse) WithCodigo(codigo int) ResultBuilder {
    r.ResultResponse.WithCodigo(codigo)
    return r
}

// 其他结构体实现类似

或者使用泛型(Go 1.18+):

type Response[T any] struct {
    ResultResponse
    Data T
}

func (r *Response[T]) WithSuccess(success bool) *Response[T] {
    r.ResultResponse.WithSuccess(success)
    return r
}

func (r *Response[T]) WithCodigo(codigo int) *Response[T] {
    r.ResultResponse.WithCodigo(codigo)
    return r
}

// 使用
type LoginData struct {
    Token      string `json:"Token"`
    ComercioId string `json:"ComercioId"`
    UsuarioId  string `json:"UsuarioId"`
}

resp := &Response[LoginData]{}
resp.WithSuccess(true).WithCodigo(100)
resp.Data.Token = "123"

最直接的方案是第一种:直接为ResultResponse定义方法,然后通过嵌入结构体来访问这些方法。这样只需要维护ResultResponse的方法,所有嵌入它的结构体都能使用。

回到顶部