如何创建具有多种返回类型的接口方法 [英] How to create an interface method with multiple return types

查看:70
本文介绍了如何创建具有多种返回类型的接口方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是此问题的后续解答:具有多种返回类型的接口方法

This is a follow up to this question: Interface method with multiple return types

我有两个结构略有不同.一种是关于交易结构的,另一种是关于转移结构的.目的是在最后计算数量.同样,交易结构应实现某些特定功能,而该功能不是转让结构所共有的,反之亦然.最后,它们都调用get()函数,并最终返回数量(类型字符串).我不能做这样的事情qtyGetService(trade{}).calculateA().get(),其中qtyGetService()get()可以从两个结构中调用,但是calculateA()是仅适用于交易结构的方法.接口首先看起来有望解决此类问题,但我正面临该问题中所述的问题

I have two structs which are slightly different. One is about a trade struct, the other about a transfer struct. The goal is to calculate the quantity at the end. Also the trade struct shall implement some specific function not common to the transfer struct and the other way around. At the end they all call a get() function and ultimately return the quantity (type string). I can't come to do something like that qtyGetService(trade{}).calculateA().get() where qtyGetService() and get() can be called from both struct, but calculateA() is a method only for trade struct. Interfaces look at first promising to solve such issues but I'm facing the issue described in that question Interface method with multiple return types that a method in an interface must return a specific type. Returning an interface{} wouldn't be an option either as I would not be able to chain the functions like shown in the example below (not even mentioning the use of reflect).

package main

import (
    "fmt"
)

type Trade struct {
    q   string
    // many other attributes
}

type Transfer struct {
    q   string
    // many other attributes
}

type TradeService struct {
    q       string
    // some other attributes
}

type TransferService struct {
    q       string
    // some other attributes
}

type GetQty struct {
    q       string
    // some other attributes
}

func qtyGetTradeService(str *Trade) *TradeService {
    // some processing on the initial struct
    return &TradeService{
        q: str.q + " TradeService ",
    }
}

func qtyGetTransferService(str *Transfer) *TransferService {
    // some processing on the initial struct
    return &TransferService{
        q: str.q + " TransferService ",
    }
}

func (ts *TradeService) calculateA() *GetQty {
    // some processing on ts
    return &GetQty{
        q: ts.q + " CalculateA ",
    }
}

func (ts *TradeService) calculateB() *GetQty {
    // some processing on ts
    return &GetQty{
        q: ts.q + " CalculateB ",
    }
}

func (ts *TransferService) calculateC() *GetQty {
    // some processing on ts
    return &GetQty{
        q: ts.q + " CalculateC ",
    }
}

func (gq *GetQty) get() string{
    // some processing on gq common to both trade and transfer
    return gq.q + " CommonGet "
}



func main() {
    // this works just fine
    fmt.Println(qtyGetTradeService(&Trade{q: "10"}).calculateA().get())
    fmt.Println(qtyGetTransferService(&Transfer{q: "10"}).calculateC().get())

    // But this would be "better" to do something like this:
    fmt.Println(qtyGetService(&Trade{q: "10"}).calculateA().get())
    fmt.Println(qtyGetService(&Transfer{q: "10"}).calculateC().get())
}

链接到游乐场: https://play.golang.org/p/SBCs_O9SL0k

推荐答案

Thx,用于重新发布问题.在另一个问题的评论中,很难提供一个代码示例.

Thx for reposting the question. In the comments of the other question it would have been hard to provide a code example.

我在这里看到2个选项:

I see 2 options you have here:

在具有相同签名的所有结构上创建函数calculate.在您的示例中,没有输入参数,只有一个返回值.如果不是这种情况,情况会变得更加复杂,选项2可能更合适.

Create a function calculate on all structs with the same signature. In your example there are no input params, only a return value. If that is not the case, things get a bit more complex and option 2 might be a better fit.

注意:链接功能使在Go中使用接口变得更加困难.您可能想要摆脱它.

Note: chaining functions makes it harder to use interfaces in Go. You might want to get rid of that.

示例:

type qty interface{
    calculate() qty // chaining can be problematic. best no return value here.
    get() string // or whatever type get should return
}

func (ts *TradeService) calculate() qty {
    ts.calculateA()
    return ts
}

func (ts *TransferService) calculate() qty {
    ts.calculateC()
    return ts
}

func main() {
    // Now this should 
    fmt.Println(qtyGetService(&Trade{q: "10"}).calculate().get())
    fmt.Println(qtyGetTransferService(&Transfer{q: "10"}).calculate().get())

    // or without chaining (if the return value is removed from `calculate`):
    printVal(qtyGetService(&Trade{q: "10"}))
    printVal(qtyGetTransferService(&Transfer{q: "10"}))
}

func printVal(service qty) {
    service.calculate()
    fmt.Println(service.get())
}

有时,即使不需要满足接口的要求,也可以在结构上实现功能.如果有不需要在调用get之前进行计算的服务,则只需创建以下函数即可:

Sometimes it makes sense to implement a function on a struct even if it is not needed to satisfy an interface. If there is a service that doesn't need to calculate before calling get just create this function:

func (ts *SomeService) calculate() {}

现在它可以用作qty界面.

也可能是因为案件的统一性和统一性较差.

It could also be that the cases are not so uniform and harder to bring into a single interface.

然后,您可以使用多个接口,并强制转换结构以检查其是否实现了该接口.只有这样才能调用该方法.这或多或少就像检查该结构是否具有某种方法.

Then you could work with multiple interfaces and cast the struct to check if it implements the interface. Only then call the method. This is more or less like a check if the struct has a certain method or not.

type calculatorA interface {
    calculateA()
}

type calculatorB interface {
    calculateB()
}

type getter interface {
    get()
}

func main() {
    service := qtyGetService(&Trade{q: "10"})
    if ok, s := service.(calculatorA); ok {
        s.calculateA()
    }
    if ok, s := service.(calculatorB); ok {
        s.calculateB()
    }
    var val string
    if ok, s := service.(getter); ok {
        val = s.get()
    }
    fmt.Println(val)
}

希望这适用于您的情况,并为您提供一些想法.

Hope this is applicable to your case and gives you some ideas.

这篇关于如何创建具有多种返回类型的接口方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆