Understanding interfaces in Go

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

Understanding interfaces in Go

问题

我正在尝试理解Go语言中接口的工作原理。

假设我有两个结构体:

package "Shape"

type Square struct {
   edgesCount int
}

type Triangle struct {
   edgesCount int
}

现在我创建了一个Shape接口:

type Shape interface {

}

为什么我不能指定Shape接口具有一个edgesCount属性?接口只能用于分组方法吗?

我面临的另一个问题是共享函数。是否可能实现类似这样的功能:

func New() *Shape {
  s := new(Shape)
  s.edgesCount = 0
  return s
}

这比重复编写完全相同的代码要好得多:

func New() *Square {
  s := new(Square)
  s.edgesCount = 0
  return s
}

func New() *Triangle {
  s := new(Triangle)
  s.edgesCount = 0
  return s
}

(这也会导致问题,因为我不能重新声明我的New函数...)

非常感谢您的帮助。

英文:

I am trying to understand how interfaces work in Go.

Let's say I have 2 structs:

package "Shape"

type Square struct {
   edgesCount int
}

type Triangle struct {
   edgesCount int
}

Now I create a Shape interface:

type Shape interface {

}

Why can't I specify that the Shape interface has an egdesCount property? Are interfaces only supposed to regroup methods?

Another problem I face is sharing function. Isn't possible to come up with something like this:

func New() *Shape {
  s:=new(Shape)
  s.edgesCount = 0
  return s
}

This would be much better than having to rewrite the exact same code:

func New() *Square {
  s:=new(Square)
  s.edgesCount = 0
  return s
}

func New() *Triangle {
  s:=new(Triangle)
  s.edgesCount = 0
  return s
}

(which also poses problem as I cannot redeclare my New function...)

Many thanks for your help

答案1

得分: 3

你所提到的不是接口(允许将对象作为该接口传递,因为对象是接口方法的接收者)。这里,一个空的interface{}类型的Shape可以满足任何类型,但在这里并不实用。

这更多涉及到类型嵌入(使用匿名类型结构):

这将会将共同的字段edgesCount提升到两个结构体中。
正如规范中提到的

struct x中的匿名字段f被称为被提升,如果x.f是一个合法的选择器,表示该字段或方法f

参考这个例子

type Shape struct {
    edgesCount int
}

type Square struct {
    Shape
}

type Triangle struct {
    Shape
}

func NewSquare() *Square {
    return &Square{
        Shape{edgesCount: 4},
    }
}
func NewTriangle() *Triangle {
    return &Triangle{
        Shape{edgesCount: 3},
    }
}

func main() {
    fmt.Printf("Square %+v\n", NewSquare())
    fmt.Printf("Triangle %+v\n", NewTriangle())
}

输出:

Square &{Shape:{edgesCount:4}}
Triangle &{Shape:{edgesCount:3}}
英文:

What you are referring to isn't interface (which allows to pass an object as that interface, simply because the object is a receiver for all the interface method).
Here, an empty interface{}' Shape would be satisfied by any type, which isn't useful here.

It is more about type embedding (using an anonymous type structure for instance):

That would promote the common field edgesCount to both struct.
As the spec mentions:

> A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.

See this example:

type Shape struct {
	edgesCount int
}

type Square struct {
	Shape
}

type Triangle struct {
	Shape
}

func NewSquare() *Square {
	return &Square{
		Shape{edgesCount: 4},
	}
}
func NewTriangle() *Triangle {
	return &Triangle{
		Shape{edgesCount: 3},
	}
}

func main() {
	fmt.Printf("Square %+v\n", NewSquare())
	fmt.Printf("Triangle %+v\n", NewTriangle())
}

Output:

Square &{Shape:{edgesCount:4}}
Triangle &{Shape:{edgesCount:3}}

答案2

得分: 2

Go不是一种面向对象的语言,而且那些字段是内部字段,因为它们以小写字母开头。相反,可以尝试以下方式:

type Shape interface {
    EdgeCount() int
}

type Square struct {
   edgesCount int
}

func (s Square) EdgeCount() int {
    return s.edgesCount
}

type Triangle struct {
   edgesCount int
}

func (t Triangle) EdgeCount() int {
    return t.edgesCount
}

现在,你可以在任何类型的对象上使用EdgeCount函数,因为它们都实现了Shape接口。

func IsItSquare(s Shape) bool {
    // 如果有4条边,可能是正方形
    return s.EdgeCount() == 4
}

但是你仍然需要使用独立的New函数或直接声明来创建不同类型的形状。

// 显然是一个假设的例子
s := Triangle{edgesCount: 3}
英文:

Go isn't an object oriented language, and those fields are internal fields since they start with lower case letters. Instead, try something like this:

type Shape interface {
    EdgeCount() int
}

type Square struct {
   edgesCount int
}

func (s Square) EdgeCount() int {
    return s.edgesCount
}

type Triangle struct {
   edgesCount int
}

func (t Triangle) EdgeCount() int {
    return t.edgesCount
}

Now you can do things using the EdgeCount function on either type of object since they both implement the Shape interface.

func IsItSquare(s Shape) bool {
    // If it has 4 sides, maybe
    return s.EdgeCount == 4
}

But you will still need to create the different types of shapes with independent New functions, or just by declaring them literally.

// Obviously a contrived example
s := Triangle{edgesCount: 3}

答案3

得分: 0

只翻译代码部分:

type Shape struct {
    edgeCount int
}

func (s Shape) EdgeCount() int {
    return s.edgeCount
}

type Square struct {
    Shape
}

type Triangle struct {
    Shape
}

func main() {
    sq := Square{Shape{edgeCount: 4}}
    tr := Square{Shape{edgeCount: 3}}
    fmt.Println(sq.EdgeCount())
    fmt.Println(tr.EdgeCount())
}

请注意,Go语言中没有代码继承的概念,但可以通过结构体嵌入来实现类似的效果。在上述代码中,SquareTriangle结构体嵌入了Shape结构体,从而可以继承Shape的方法和属性。

英文:

Interface only group methods, as their purpose is to define behavior, very much like in other languages (see Java Interfaces, for example).

What you are looking for is something like code inheritance, which doesn't exist in Go. BUT, you can get something similar with struct embedding:

>Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.

So, you can get what you want by doing the following (play link):

type Shape struct {
    edgeCount int
}

func (s Shape) EdgeCount() int {
    return s.edgeCount
}

type Square struct {
    Shape
}

type Triangle struct {
    Shape
}

func main() {
    sq := Square{Shape{edgeCount: 4}}
    tr := Square{Shape{edgeCount: 3}}
	fmt.Println(sq.EdgeCount())
    fmt.Println(tr.EdgeCount())
}

huangapple
  • 本文由 发表于 2015年1月23日 02:19:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/28095956.html
匿名

发表评论

匿名网友

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

确定