Как в Go реализуется утиная типизация и в чем ее преимущество?

Ответ

В Go утиная типизация реализуется через интерфейсы. Тип данных неявно удовлетворяет интерфейсу, если он реализует все методы, объявленные в этом интерфейсе. Явное указание implements (как в других языках) не требуется.

Преимущество такого подхода заключается в слабой связанности (loose coupling) компонентов системы. Вы можете создавать функции, которые работают с любым типом, реализующим нужный интерфейс, что делает код более гибким, переиспользуемым и тестируемым.

Пример:

package main

import "fmt"

// Speaker определяет поведение "умение говорить"
type Speaker interface {
    Speak() string
}

// Dog реализует интерфейс Speaker неявно
type Dog struct{}

func (d Dog) Speak() string { return "Гав!" }

// Human тоже реализует Speaker
type Human struct{}

func (h Human) Speak() string { return "Привет!" }

// Функция работает с любым типом, удовлетворяющим Speaker
func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    MakeSound(Dog{})
    MakeSound(Human{})
}

В этом примере и Dog, и Human могут быть переданы в функцию MakeSound, потому что они оба "крякают как утка", то есть имеют метод Speak() string. Это и есть утиная типизация в действии.