Тип возврата интерфейса Go
У меня есть такой интерфейс:
type ViewInterface interface{
Init() View
}
type View struct{
Width int
Height int
}
Поэтому я создаю новый тип из View
type MainView View
func (m MainView) Init() MainView{
return MainView{
Width:10,
Height:10,
}
}
затем я передаю MainView к следующему методу:
func Render(views ...ViewInterface){
for _, view := range views {
v := view.Init()
}
}
func main() {
Render(MainView{})
}
Но я получаю эту ошибку:
нельзя использовать литерал MainView (тип MainView) как тип ViewInterface в аргументе для Render: MainView не реализует ViewInterface (неправильный тип для метода Init)
есть Init() MainView
хочу Init () Просмотр
Зачем MianView
не то же самое, что View
? Как правильно решить эту проблему?
Спасибо
2 ответа
GO имеет другую модель наследования по сравнению с основными языками, такими как Java и C#.
Почему MianView отличается от View?
Потому что они определены по-разному.
Init
функция MainView
возвращается MainView
в то время как интерфейс требует возврата View
,
Подпись Init
Метод выглядит странно, он требует экземпляра структуры, потому что он является структурным методом и возвращает новый экземпляр того же типа структуры.
Попытайтесь спроектировать интерфейс вокруг логики ваших структур вместо их конструкции / времени жизни:
type ViewInterface interface{
Render()
}
type MainView View
func (m MainView) Render() {
// do something
}
type AnotherView
func (m AnotherView) Render() {
// do something else
}
func Render(views ...ViewInterface){
for _, view := range views {
view.Render()
}
}
Так как type MainView View
является "определенным типом" и "отличается от любого другого типа, включая тип, из которого он создан.".
Вместо этого вы можете использовать псевдоним типа. type MainView = View
,
Но на самом деле проблема заключается в дизайне ViewInterface
а также Init()
,
Init()
написано как метод класса. У Go нет методов класса (или, строго говоря, классов). Вы создаете структуру и вызываете методы для нее. Простая инициализация может быть сделана прямо тогда.
view := View{ Width: 10, Height: 10 }
Если вы хотите определить метод для последовательной инициализации значений, он будет действовать на существующую структуру и ничего не будет возвращать.
type ViewInterface interface{
Init()
}
type View struct{
Width int
Height int
}
func (v *View) Init() {
v.Width = 10
v.Height = 10
}
view := View{}
view.Init()
затем MainView
также можно определить Init()
,
type MainView struct {
X int
Y int
}
type (mv *MainView) Init() {
mv.X = 23
mv.Y = 42
}
Так как Init()
берет указатель, чтобы удовлетворить ViewInterface
Вы должны передать в указателях.
func main() {
view := View{}
mv := MainView{}
Render(&view, &mv)
}
Но что это Render()
делать инициализацию объектов в любом случае? Это уже должно быть сделано. Это должен быть рендеринг. Интерфейсы должны быть связаны с общей функциональностью, независимо от того, как она реализована. Вещи, реализующие ViewInterface, уже должны быть инициализированы.
Вместо этого вы можете сказать, что ViewInterface
должен иметь Render
метод.
type ViewInterface interface{
Render()
}
затем View
а также MainView
может быть структурирован, как вам нравится, пока они реализуют Render()
,
func (v View) Render() {
fmt.Println("View!")
fmt.Println(v)
}
func (mv MainView) Render() {
fmt.Println("MainView!")
fmt.Println(mv)
}
ЗатемRender()
может взять список вещей, которые реализуют ViewInterface
и позвонить Render()
на каждом из них.
func Render(views ...ViewInterface){
for _, view := range views {
view.Render()
}
}
Инициализируйте их, прежде чем передавать их. И теперь нет необходимости передавать указатели.
func main() {
view := View{}
view.Init()
mv := MainView{}
mv.Init()
Render(view, mv)
}
Наконец, Маркус предложил в комментариях использовать пакет, чтобы получить что-то вроде методов класса.
# viewtest/main.go
package main
import(
"log"
"viewtest/view"
)
func main() {
v := view.New()
log.Printf("%#v", v)
}
# viewtest/view/view.go
package view
type View struct {
Width int
Height int
}
func New() View {
return View{Width: 10, Height: 10}
}
Пакеты Go требуют некоторого привыкания. Go имеет четкие представления о том, как должен быть структурирован ваш проект. Я предлагаю этот урок.