与返回自身的方法的接口

问题描述 投票:0回答:2

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作为其两个属性之一的struct Num。现在,我希望我的包的用户能够使用big.RatFrac64int64rune或他们想要的任何东西,只要他们实现Num接口。

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

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

我没有为Num实施Frac,因为我无法从Frac64Add函数调用FracAdd

go interface
2个回答
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是一个带有一些扩展的NumFrac应该是一个扩展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


0
投票

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

func (a Frac64) Add(b Num) Num {
    // Pretend this is implemented
    // It can return anything that implements Num
}
© www.soinside.com 2019 - 2024. All rights reserved.