【问题标题】:Interface with methods that return itself与返回自身的方法的接口
【发布时间】:2018-03-06 20:35:52
【问题描述】:

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? }

我将如何为Frac 实现Add 以便它实现Num 接口?

编辑:附加信息

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

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

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

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

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

【问题讨论】:

  • PlusTerm 从未被引用。我不清楚你想要完成什么。一些代码来显示您希望它如何工作会有所帮助。
  • 您是否将Rat from the big package 重新实现为练习?
  • 我应该在原帖中写下更多信息。我试图创建一个展示我的问题的最小示例。结构本身可以是任何东西。使用 Frac64,我尝试使用 Add 函数创建一个不可变结构的最小示例。在客户端中,我正在尝试为 Frac 实现 Num 接口,这是一个 typedef Frac64,它还具有与 Num 的 Add 不匹配的 Add 函数。
  • 我基本上希望将我的包与Term 结构一起使用的人能够使用他们认为适合用作系数的任何结构,只要它实现了 Num。
  • 接口不完整,恕我直言。如果 Add 方法的参数不是 Frac64,如何捕获案例?你如何转换它?还是返回错误?您应该添加一个方法来获取数字的两个部分或将其转换为 ex。

标签: go interface


【解决方案1】:

你可以用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,
    }
}

这可行,但是从更具体的类型 Frac64 构建不太具体的类型 Frac 很尴尬。

从这里可以更明显地看出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

【讨论】:

  • 感谢您的详尽回答。我在我的帖子中添加了一些额外的信息。您的两个建议都更改了Frac64Add 函数,但我不能这样做,因为它在外部包中。
  • 我遇到了这个问题,这似乎很清楚地解释了我的问题:stackoverflow.com/a/43507669/2966323 我想我需要使用嵌入而不是别名来访问方法
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2018-07-09
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 2016-02-29
    • 2017-05-09
    相关资源
    最近更新 更多