Как Go повышает производительность с «неявными» интерфейсами и как это соотносится с понятием C # методов расширения?

21

В руководстве по языку Go они объясняют, как работают интерфейсы:

Сразу нет классов. Однако вы можете определить методы для структурных типов. Приемник метода появляется в своем списке аргументов между Func ключевым словом и именем метода.

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Тип интерфейса определяется набором методов. Значение типа интерфейса может содержать любое значение, которое реализует эти методы.

Это единственный способ создать интерфейс в Go. Google далее объясняет, что:

Тип реализует интерфейс путем реализации методов. Нет явного объявления о намерениях [т.е. interfaceобъявлений].

Неявные интерфейсы отделяют пакеты реализации от пакетов, которые определяют интерфейсы: ни один не зависит от другого.

Это также поощряет определение точных интерфейсов, потому что вам не нужно искать каждую реализацию и помечать ее новым именем интерфейса.

Все это звучит подозрительно как методы расширения в C # , за исключением того, что методы в Go беспощадно полиморфны; они будут работать с любым типом, который их реализует.

Google утверждает, что это способствует быстрому развитию, но почему? Вы отказываетесь от чего-то, уходя от явных интерфейсов в C #? Могут ли методы расширения в C # позволить извлечь некоторые из преимуществ интерфейсов Go в C #?

Роберт Харви
источник
Связанный: stackoverflow.com/q/11441905
Роберт Харви
1
Эти интерфейсы Go более похожи на то, что могут делать шаблоны C ++, чем на методы расширения C #. В C # нет ничего подобного «любому типу, который реализует методы A и B», но вы можете сделать это, используя шаблоны C ++.
svick
Связанный: codeproject.com/Articles/9281/…
Роберт Харви
Разве «неявные интерфейсы» - это не просто форма утки?
Аллон Гуралнек
«Разве« неявные интерфейсы »- это не просто форма утки?» Интерфейсы Go являются примером структурной типизации. Очень похожая концепция.
Смерть

Ответы:

12

Я не вижу методов расширения и неявных интерфейсов одинаковыми вообще.

Сначала поговорим о цели.

Методы расширения существуют как синтаксический сахар специально для того, чтобы дать вам возможность использовать метод, как если бы он был членом объекта, не имея доступа к внутренним объектам этого объекта. Без методов расширения вы можете делать то же самое, вы просто не получаете приятный синтаксис someObjectYouCantChange.YourMethod()и, скорее, вынуждены вызывать YourMethod(someObjectYouCantChange).

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

Теперь поговорим о последствиях.

Методы расширения на самом деле не имеют ни одного, это полностью соответствует безжалостным ограничениям безопасности, которые .NET пытается использовать, чтобы помочь в различных точках зрения на модель (перспектива изнутри, снаружи, наследник и сосед). Следствием этого является лишь некоторая синтаксическая приятность.

Последствия неявных интерфейсов - это несколько вещей.

  • Случайная реализация интерфейса, это может быть счастливый случай или случайное нарушение LSP при встрече с чужим интерфейсом, который вы не собирались выполнять, не соблюдая при этом намерения его контракта.
  • Возможность легко заставить любой метод принимать макет любого данного объекта, просто отражая интерфейс этих объектов (или даже просто создавая интерфейс, который отвечает требованиям этих методов и не более).
  • Возможность создавать адаптеры или другие различные похожие шаблоны с большей легкостью в отношении объектов, в которые вы не можете вмешиваться во внутренностях.
  • Отложите реализацию интерфейса и реализуйте ее позже, не касаясь фактической реализации, а реализуйте ее только тогда, когда вы действительно хотите создать другого разработчика.
Джимми Хоффа
источник
Полезность методов расширения в Linq в значительной степени обусловлена ​​их способностью прививать реализацию метода к интерфейсу, в частности IEnumerableи IQueryable. Хотя вы можете подделать это с помощью staticметодов в служебном классе, это будет неуклюже.
Роберт Харви
@RobertHarvey Не обязательно точно утверждать, что он помещает метод в интерфейс, обратите внимание на разницу между фактическим методом в интерфейсе и методом расширения: метод в интерфейсе будет реализован внутри класса, который реализует этот интерфейс, и поэтому имеет доступ к гораздо большему, чем любой метод расширения. Опять же, это изменение в перспективе, код, реализованный внутри класса, имеет особую перспективу по сравнению с внешним.
Джимми Хоффа