Комментарии 19
func (Human) SayHello() {
fmt.Println("Hello")
}
Должно быть:
func (h Human) SayHello() {
fmt.Println(h.Greeting)
}
В Go структура с методами будет удовлетворять интерфейсу просто самим фактом объявления метода. Это кажется не особо важным на маленьких программах или искусственных примерах, но оказывается ключевым в больших проектах, где приходится думать дважды перед тем как изменить какой-то класс, многократно унаследованный другими классами.
Классы, наследование в go?
type (
MyFloat float64
MyString string
)
Напоминает джавовские типы Integer, Float, и т.д. Джававская модель дженериков тоже требует wrapper-ов для примитивных типов.
Видел недавно в твиттере наброс от функциональщика: twitter.com/itchyankles/status/674174588369113088
Go People: Given 2 functions (1 for `[]MyType1` & 1 for `[]MyType2`) that are 100% identical. Do I have to copy paste code or type cast?
Тут человек полностью заблудился. Если MyType1 и MyType2 полностью идентичны, то они и должны быть одного типа. С точки зрения Go, даже если под капотом и тот и другой — string, это всё равно абсолютно разные типы, так как могут реализовать разные методы. MyType1 может удовлетоврять какому-то интерфейсу, а MyType2 — нет.
MyInt does not implement Item (wrong type for Less method)
have Less(MyInt) bool
want Less(Item) bool
Даже в языках поддерживающих ко-/контравариантность типов это бы не сработало, тк Less(Item) может принимать не только объекты MyInt
Здесь кроется проблема подобного обобщённого программирования — в методе Less придётся использовать type assertion, что не особенно эффективно
Спасибо за статью, но я не понял практический смысл интерфейсов. Поправьте меня, пожалуйста:
1. Go — интерфейс не может содержать данные, только методы.
2. Go — интерфейс привязывается неявно (duck typing).
Т.е. если я создаю структуру, которая должна реализовать методы интерфейса, но забываю реализовать метод Render(), то:
— При попытке вызвать метод, я огребаю ошибку, что нет метода. Как собственно и без интерфейса.
— Если я вдруг явно не вызываю метод, то мне и компилятор не сообщит об ошибке, что метод не реализован. Явной же привязке к интерфейсу нет.
В итоге мне сейчас видеться, что интерфейсы — это некая лишняя абстракция. Я понимаю что ваш пример из статьи упрощен, но он легко работает и без интерфейса: play.golang.org/p/9yvjWwqtTAv.
Единственное достойное применение — это случай, описанный у вас с «MyString и MyFloat». Во всех остальных случаях, вроде как, интерфейсы излишни.
Или я ошибаюсь? Приведите, пожалуйста, еще примеры.
Привет.
Смотрите, допустим вы пишете код, который должен работать с объектами, которые умеет рендерить (упомянутый вами метод Render()) для этого) — скажем UI фреймворк, в котором каждый виджет описывает как он рендерится.
Если у вас всего один такой тип (ну, там, type Window struct{}
) – то интерфейс вам не нужен, вы просто везде указываете тип Window и с ним работаете. Компилятор знает, что у этого типа есть метод Render() и вызывает его когда надо.
Если же у вас 100 разных виджетов, то какой тип вы будете передавать в функциях внутри вашего кода? Например, у вас есть метод resizeWidget(w .???) { w.Render(); }
— какого типа должен быть параметр w? Вам нужно как-то мочь логически обобщить все ваши виджеты в одну группу и сказать – они тут все подходят, докуда у них есть метод Render()
.
Вот именно тут и пригождаются интерфейсы – они говорят "плевать какой там конкретный тип, главное чтобы у него был метод Render()`.
Главный бенефит начинается от этого, когда у вас есть много разного кода, написанного разными командами/людьми в разное время. Например, ваш UI движок работающий с интерфейсом Widget
(или Renderer
) совершенно понятия не имеет какие ему будут передавать виджеты. Любой юзер через 5 лет может написать свой виджет и спокойно его использовать в вашем код – они decoupled и не зависят напрямую друг от друга. Движку не нужно знать ничего о типе вашего виджета, чтобы с ним работать.
Так немного яснее? :)
Краш-курс по интерфейсам в Go