2015-01-22 3 views
0

Я пытаюсь понять, как интерфейсы работают в Go.Понимание интерфейсов в Go

Скажем, у меня есть 2:

Структуры
package "Shape" 

type Square struct { 
    edgesCount int 
} 

type Triangle struct { 
    edgesCount int 
} 

Теперь я создаю Shape интерфейс:

type Shape interface { 

} 

Почему я не могу указать, что интерфейс Shape имеет egdesCount свойство? Используются ли интерфейсы только для перегруппировки методов?

Еще одна проблема, с которой я сталкиваюсь, - это функция совместного использования. Не представляется возможным, чтобы придумать что-то вроде этого:

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 функция ...)

Большое спасибо за вашу помощь

+0

Обратите внимание, что Go также позволяет лаконична альтернативные 'SquareEdges типа int', для объявления типов, которые имеют один основной значение данных. Все остальное здесь обсуждалось и яблоки для этих красных типов. –

ответ

3

Что вы имеете в виду не интерфейс (который позволяет передавать объект, как этот интерфейс, просто потому, что объект является приемником для всех метода интерфейса).
Здесь empty interface{}' Shape would be satisfied by any type, что здесь не полезно.

Это больше о type embedding (используя anonymous type structure, например):

Это будет способствовать общее поле edgesCount как для структуры.
Как spec mentions:

Поле или метод f анонимного поля в struct x называется способствует, если x.f является законным селектор, который обозначает, что поле или метод f.

См 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()) 
} 

Выход:

Square &{Shape:{edgesCount:4}} 
Triangle &{Shape:{edgesCount:3}} 
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 { 
    // If it has 4 sides, maybe 
    return s.EdgeCount == 4 
} 

Но вам все равно нужно создавать различные типы фигур с независимыми новыми функциями, или просто объявив их буквально.

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

только Интерфейсные групповые методы, так как их цель состоит в том, чтобы определить поведение, очень похоже на других языках (см Java Interfaces, например,).

Что вы ищете, это нечто вроде наследования кода, которого нет в Go. НО, вы можете получить что-то подобное с struct embedding:

Go не обеспечивает типичное, типа с приводом понятия подклассов, но у него есть возможность «одолжить» часть реализации путем встраивания типов в структуры или интерфейс.

Таким образом, вы можете получить то, что вы хотите, выполнив следующие (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()) 
}