W jaki sposób Go poprawia produktywność dzięki „niejawnym” interfejsom i jak to się ma do koncepcji metod rozszerzenia w języku C #?

21

W samouczku na temat języka Go wyjaśniają, w jaki sposób działają interfejsy:

Go nie ma zajęć. Można jednak zdefiniować metody dla typów struktur. Odbiornik metoda pojawia się we własnym listy argumentów pomiędzy hasła funk i nazwy metody.

type Vertex struct {
    X, Y float64
}

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

Typ interfejsu jest definiowany przez zestaw metod. Wartość typu interfejsu może zawierać dowolną wartość implementującą te metody.

Jest to jedyny sposób na utworzenie interfejsu w Go. Google wyjaśnia dalej, że:

Typ implementuje interfejs poprzez implementację metod. Nie ma wyraźnej deklaracji woli [tj. interfaceDeklaracji].

Interfejsy niejawne oddzielają pakiety implementacyjne od pakietów, które definiują interfejsy: żaden nie zależy od drugiego.

Zachęca również do definiowania precyzyjnych interfejsów, ponieważ nie musisz znajdować każdej implementacji i oznaczać ją nową nazwą interfejsu.

To wszystko wygląda podejrzanie jak Metody rozszerzeń w C # , z tym wyjątkiem, że metody w Go są bezwzględnie polimorficzne; będą działać na każdym rodzaju, który je implementuje.

Google twierdzi, że zachęca to do szybkiego rozwoju, ale dlaczego? Czy coś rezygnujesz, odchodząc od jawnych interfejsów w C #? Czy metody rozszerzeń w języku C # pozwalają uzyskać niektóre korzyści, jakie interfejsy Go mają w języku C #?

Robert Harvey
źródło
Powiązane: stackoverflow.com/q/11441905
Robert Harvey
1
Te interfejsy Go brzmią bardziej jak możliwości szablonów C ++ niż metody rozszerzenia C #. W języku C # nie ma to jak „dowolny typ, który implementuje metody A i B”, ale można to zrobić za pomocą szablonów C ++.
svick
Powiązane: codeproject.com/Articles/9281/…
Robert Harvey
Czy „niejawne interfejsy” nie są tylko formą pisania kaczek?
Allon Guralnek
„Czy„ niejawne interfejsy ”nie są tylko formą pisania kaczek?” Interfejsy Go są przykładem pisania strukturalnego. Bardzo podobna koncepcja.
mortdeus,

Odpowiedzi:

12

W ogóle nie widzę metod rozszerzenia i niejawnych interfejsów.

Najpierw porozmawiajmy o celu.

Metody rozszerzeń istnieją jako cukier składniowy, aby dać ci możliwość użycia metody tak, jakby była elementem obiektu, bez dostępu do wewnętrznych elementów tego obiektu. Bez metod rozszerzenia możesz zrobić dokładnie to samo, po prostu nie masz przyjemnej składni someObjectYouCantChange.YourMethod()i raczej musisz zadzwonić YourMethod(someObjectYouCantChange).

Interfejsy niejawne mają jednak na celu zaimplementowanie interfejsu na obiekcie, do którego zmiany nie masz dostępu. Daje to możliwość tworzenia polimorficznej relacji między dowolnym obiektem, który sam piszesz, a dowolnym obiektem, którego nie masz dostępu do wewnętrznych elementów.

Porozmawiajmy teraz o konsekwencjach.

Metody rozszerzeń tak naprawdę nie mają, jest to całkowicie zgodne z bezwzględnymi ograniczeniami bezpieczeństwa .NET próbuje użyć, aby pomóc w różnych perspektywach modelu (perspektywa od wewnątrz, z zewnątrz, spadkobierca i sąsiada). Konsekwencją jest tylko pewna składniowa przyjemność.

Konsekwencje domniemanych interfejsów to kilka rzeczy.

  • Przypadkowa implementacja interfejsu, może to być szczęśliwy wypadek lub przypadkowe naruszenie LSP przez spotkanie z interfejsem innej osoby, którego nie zamierzałeś, nie respektując intencji jego umowy.
  • Możliwość łatwego spowodowania, że ​​dowolna metoda akceptuje próbkę dowolnego obiektu, po prostu dublując interfejs tego obiektu (lub nawet tworząc interfejs spełniający wymagania tej metody i nie więcej).
  • Możliwość tworzenia adapterów lub innych podobnych wzorów z większą łatwością w odniesieniu do obiektów, których nie można wtrącać się w wnętrzności.
  • Opóźnij implementację interfejsu i zaimplementuj ją później bez konieczności dotykania faktycznej implementacji, implementując ją tylko wtedy, gdy naprawdę chcesz utworzyć innego implementatora.
Jimmy Hoffa
źródło
Przydatność metod rozszerzenia w Linq wynika w dużej mierze z ich zdolności do przeszczepienia implementacji metody na interfejs, w szczególności IEnumerablei IQueryable. Chociaż można to sfałszować staticmetodami w klasie użyteczności, byłoby to nieporadne.
Robert Harvey
@RobertHarvey Niekonieczne jest twierdzenie, że umieszcza metodę na interfejsie, zwróć uwagę na różnicę między rzeczywistą metodą interfejsu a metodą rozszerzenia: metoda interfejsu zostanie zaimplementowana wewnątrz klasy, która implementuje ten interfejs, a zatem ma dostęp do znacznie więcej niż jakiejkolwiek metody rozszerzenia. Znowu jest to zmiana perspektywy, kod zaimplementowany w klasie ma specjalną perspektywę w porównaniu do tej na zewnątrz.
Jimmy Hoffa