与返回自身的方法的接口

时间:2018-03-05 20:58:53

标签: go interface

包裹term

type Num interface {
    IsNeg()  bool
    Add(Num) Num
}

type Term struct {
    Coeff Num
    Var   string
}

外部包frac64

type Frac64 struct {
    Numer uint64
    Denom uint64
    Neg   bool
}

func (a Frac64) Add(b Frac64) Frac64 { // Pretend this is implemented }

套餐client

type Frac Frac64

func (f Frac) IsNeg()  bool   { return f.Neg }
func (f Frac) Add(v Num) Num  { // Call Frac64's Add here? }

我如何为Add实施Frac,以便它实现Num界面?

编辑:其他信息

外部包frac64只是一个例子。我不打算用它。

这里的目标(我应该更清楚)是我的包公开了使用Term作为其两个属性之一的结构Num。现在,我希望我的包的用户能够使用big.RatFrac64int64rune或他们想要的任何内容,只要他们实现{{1接口。

我遇到的问题是尝试为已经具有与Num中的函数同名的函数的结构实现Num接口。这是Num的用武之地。我也可以使用Frac64作为示例,因为它还有一个名为big.Rat的函数。

我无法更改Add(或Frac64的实现),而且我也无法使用big.Rat函数扩展它,因为它已经存在。这就是为什么我尝试使用Add(或type Frac Frac64)然后尝试扩展type Frac big.Rat

我无法为Frac实施Num,因为我无法从Frac的{​​{1}} Frac64 Add { {1}}功能。

2 个答案:

答案 0 :(得分:2)

您可以使用embedding ...

解决此问题
type Frac struct {
    *Frac64
}

现在Frac可以使用Frac64的方法,无需重写它们。

// `Frac.New(numer, denom, bool)` would remove this implementation leak.
foo := Frac{
    &Frac64 {
        Numer: 45,
        Denom: 99,
        Neg: false,
    },
}
fmt.Println(foo.IsNeg())

但是当我们尝试使用Add时会遇到麻烦。

// cannot use foo (type Frac) as type Frac64 in argument to foo.Frac64.Add
fmt.Println(foo.Add(foo))

嵌入仅适用于继承方法。当用作参数时,它不会为您使用嵌入式引用,您必须明确地这样做。

真正的问题是func (a Frac64) Add(b Frac64) Frac64不满足Num接口。如果我们修复它可以正常工作,因为Frac实现了Num

func (a Frac64) Add(b Num) Num {
    return Frac64{
        Numer: 12,
        Denom: 23,
        Neg: false,
    }
}

这很有效,但是从更具体的类型Frac构建一个不太具体的类型Frac64很尴尬。

从这里开始,Frac是一个带有一些扩展名的Num变得更加明显。 Frac应该是一个扩展Num并添加分子和分母的接口。 Frac64成为实施Frac的类型。

type Num interface {
    IsNeg()  bool
    Add(Num) Num
}

type Frac interface {
    Numer() uint
    Denom() uint
    Num
}

type Frac64 struct {
    numer uint64
    denom uint64
    neg bool
}

func (f Frac64) IsNeg() bool {
    return f.neg
}

func (f Frac64) Numer() uint {
    return uint(f.numer)
}

func (f Frac64) Denom() uint {
    return uint(f.denom)
}

func (a Frac64) Add(b Num) Num {
    // Just a placeholder to show it compiles.
    return Frac64{
        numer: 12,
        denom: 34,
        neg: false,
    }
}

这对练习来说没什么问题。在制作中,请考虑使用big.Rat

答案 1 :(得分:0)

您实现它以使其具有与接口相同的签名;因此必须将其命名为Add,它必须采用类型Num的单个参数,并且必须返回类型为Num的单个值。请注意,这并不意味着它可以获取或返回实现Num 的类型的值 - 签名必须相同

func (a Frac64) Add(b Num) Num {
    // Pretend this is implemented
    // It can return anything that implements Num
}
相关问题