Как стать автором
Обновить

Комментарии 19

А про Катю-то где? :(
Не тот автор
Я, в общем-то, прекрасно это вижу
Кажется, что это примере:

func (Human) SayHello() {
    fmt.Println("Hello")
}


Должно быть:

func (h Human) SayHello() {
    fmt.Println(h.Greeting)
}

Точно, спасибо, исправлено )
В Go структура с методами будет удовлетворять интерфейсу просто самим фактом объявления метода. Это кажется не особо важным на маленьких программах или искусственных примерах, но оказывается ключевым в больших проектах, где приходится думать дважды перед тем как изменить какой-то класс, многократно унаследованный другими классами.

Классы, наследование в go?
Нет, это была отсылка к «большим проектам» на C++/Java.
Спасибо, отличная статья!
Я конечно новичёк, но в примере с MyFloat MyString не вижу особых плюсов в том, чтобы писать свои типы, потом при отправке в канал преобразовывать в них данные стандартных типов, в которых обычно и приходят данные с других библиотек, таких как mgo. Не проще тогда сразу преобразовывать в, например, string при получении из источника float?
Ну, это хороший вопрос. Пример искусственный, поэтому утверждать, что лучше, а что хуже — не совсем корректно, но тут суть в корректных абстракциях. Фунция Display может себе позволить не знать абсолютно ничего о типах — она знает лишь то, что эти значения она может отображать(рендерить), тоесть, по сути, она типонезависима (если иметь ввиду типы — статические типы). Она не знает, что это за данные, откуда они приходят, проще или не проще их преобразовывать, она даже не знает, что там под капотом — стринг, или миллион структур.
Ну если в этом смысле, то да, может пример не совсем удачный… Все же любой инструмент должен применяться к своему случаю.
В Java интерфейс может содержать только константы (final variables), а не переменные. Так что никто поведение и данные не мешает.
Спасибо, да, меня уже поправили. Но всё же, константы — это тоже данные. Такого чёткого разделения концепций поведения и данных, как в Go, всё же нет.
type (
    MyFloat  float64
    MyString string
)


Напоминает джавовские типы Integer, Float, и т.д. Джававская модель дженериков тоже требует wrapper-ов для примитивных типов.
Тут немного в другом идея — нельзя навешивать методы на стандартные типы. Тоесть, если вы добавляете метод к типу — вы меняете его поведение, и для этого есть причина. Это уже не просто string, это уже некая новая сущность. которой должно быть дано новое имя.

Видел недавно в твиттере наброс от функциональщика: 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 не удовлетворяет интерфейсу Item

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 и не зависят напрямую друг от друга. Движку не нужно знать ничего о типе вашего виджета, чтобы с ним работать.


Так немного яснее? :)

Да, спасибо.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации