依赖于接口的 Golang 接口

huangapple go评论86阅读模式
英文:

golang interface that depends on interface

问题

我不确定这是否应该是两个独立的问题还是一个问题的两个部分,但在我看来,这是一个由两个部分组成的问题:接口如何使用?我有以下两个问题:

  1. 接口的方法是全局作用域的:如果我有接口A和接口B,它们都实现了相同的方法Foo,但参数或返回类型不同,我无法同时从同一类型实现这两个接口。例如,我在一个接口中有一个返回类型为[]byte的GetBytes()方法,在另一个接口中有一个返回类型为([]byte, error)的GetBytes()方法。我该如何解决这个问题?

  2. 我遇到的另一个问题是,当我尝试定义一个接口A,该接口具有返回在同一层中定义的接口B的方法时。现在,如果我想创建一个实现A接口的对象,如果我返回一个实现B接口的结构体,Go语言无法智能地推断出该方法实现了A接口的方法,它会强制我在A接口中创建对B接口的依赖。这似乎完全违背了Go语言中接口工作方式的初衷。我该如何避免这个问题?

例如,如果我有以下代码:

type B interface {
    Bar()
}

type A interface {
    Foo() B
}

type b_impl struct{}

func (b b_impl) Bar() {}

type a_impl struct{}

// 错误的写法
func (a a_impl) Foo() b_impl {}

上述代码中的a_implFoo方法无法满足接口A的要求,我需要将其改为:

func (a a_impl) Foo() B {}

这样就会对声明B的包产生依赖。

英文:

I am not sure if these should be two separate questions or one, but it seems to me as one question of two parts - How go interfaces are supposed to be used? I have this two struggles:

The methods of the interfaces are globally scoped: If I have interface A and interface B that both implement the same method Foo, but with different arguments or return types I am unable to implement both at the same time from the same type. For example, I have GetBytes() method in one interface having return type []byte and in another ([]byte, error) How I should overcome this issue?

Another issue I have is when I try to define interface say interface A that has a method that returns interface B that is defined in the same layer. Now if I want to create an object that implements A, if I return struct that implements B go is not smart enough to deduce that this method implements the method in A and it forces me to create dependency on B. This seems to completely defeat the point of the way interfaces work in go at first place. How can I avoid this issue?

for example, if I have:

type B interface {
    Bar()
}

type A interface {
    Foo() B
}

for the following structs :

type b_impl struct{}

func (b b_impl) Bar() {}

type a_impl struct{}

A foo method

func (a a_impl) Foo() b_impl {}

does not satisfy the interface A and I need to make it:

func (a a_impl) Foo() B {}

which makes a dependency to the package where B is declared.

答案1

得分: 2

第一个问题:
在Go语言中,当你想要执行不同的任务时,你需要创建不同的函数名。让我们看看标准库中的strconv包是如何解决这个问题的:https://golang.org/pkg/strconv/#pkg-index

请注意其中append函数的不同声明。每种不同的类型都有相应的函数。

因此,如果你期望有一个名为FooInt的函数,你的接口也应该是FooInter,...

第二个问题:
作为一个小例子,当你想要使用io.Writer接口时,你不需要导入整个io包。将Writer的声明复制到你自己的包中是完全可以的。如果你正确地这样做了,每个实现了io.Writer接口的实现都会自动实现你自己的Writer接口。

在阅读其他评论后,也许你有不同的情况:

假设有一个包a和b,其中包含接口a.A和b.B。如果存在以下情况:

type A interface{
  Foo() b.B
}

并且你需要为a.A编写一个实现,那么你需要导入包b。但这不会使你的二进制文件变得更大,因为你总是需要导入包a,而包a依赖于包b。

英文:

1st question:
In go you need to make different function names, when you want to do different tasks. Let's look into the standard library at the strconv package how things are solved there: https://golang.org/pkg/strconv/#pkg-index

Look to the different declaration of the append function there. There are functions for every different type.

So if you expect a FooInt funtion your interface should be also a FooInter, ...

2nd question:As a small example. You don't need to import the whole io package, when you want to use the io.Writer interface. It is totaly ok to copy the Writer declaration into your own package. If you do that correct, every io.Writer implementation will automatically implement your own Writer interface.

After reading the other comments maybe you have a different situation:

Let's say there is a package a and b with the interface a.A and b.B. If there is the situation that:

type A interface{
  Foo() b.B
}

and you have to write an implementation for a.A, then you need to import package b. But that makes your binaries not bigger, because you will always need to import package a, which depends on b.

答案2

得分: 0

实现接口时,需要具有完全相同的方法名称和签名。这意味着签名必须具有相同的类型。

尽管看起来很奇怪,但这两个方法的签名并不相同:

Foo() B
Foo() b_impl {}

即使 b_impl 实现了 B 接口也无关紧要。

为了克服需要导入声明 B 的包的需求,可以使用匿名类型。这样编译器就不会对方法签名需要特定类型。

type A interface {
    Foo() interface{Bar()}
}

也可以通过嵌入 B 来实现:

type A interface {
    Foo() interface{B}
}

然而,a_impl 必须具有相同的签名,因此它也需要返回一个匿名接口。你还可以在 a_impl 所在的包中声明相同的 B 接口,并将其嵌入到匿名接口中。

package impl

type B interface {
	Bar()
}

type b_impl struct{}

func (b b_impl) Bar() {}

type a_impl struct{}

func (a a_impl) Foo() interface{B} {
	return b_impl{}
}

我不知道这是否是一种不好的做法,可能在某些情况下需要重新设计而不是这样做。

英文:

For implementing an interface, you need to have exactly the same method name and signature. Means the signature must be with the same types.

As much as it seems weird, these two don't have the same signature:

Foo() B
Foo() b_impl {}

It doesn't matter that b_impl implements B.

To overcome the need to import the package B is declared in, you can use anonymous type. This way the compiler won't require a specific type for the method signature.

type A interface {
    Foo() interface{Bar()}
}

Which also can be written as embedding B:

type A interface {
    Foo() interface{B}
}

Still, a_impl must have same signature, so it also needs to return an anonymous interface. You can also declare the same B interface in the package of a_impl, and embed it in an anonymous interface.

package impl

type B interface {
	Bar()
}

type b_impl struct{}

func (b b_impl) Bar() {}

type a_impl struct{}

func (a a_impl) Foo() interface{B} {
	return b_impl{}
}

I don't know if it's a bad practice or not, probably there are cases which redesign is required instead of doing this.

huangapple
  • 本文由 发表于 2016年8月24日 02:08:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/39108004.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定