Как в Go проверить, удовлетворяет ли структура интерфейсу?

Ответ

В Go удовлетворение интерфейсу происходит неявно (duck typing). Если структура реализует все методы интерфейса, она автоматически ему удовлетворяет. Проверить это можно статически (на этапе компиляции) или динамически (во время выполнения).

1. Статическая проверка (во время компиляции)

Это предпочтительный способ, так как он позволяет отловить ошибки до запуска программы. Для этого используется специальная идиома: присваивание nil-указателя на структуру переменной типа интерфейса. Если код компилируется, значит, структура удовлетворяет интерфейсу.

package main

type Writer interface {
    Write([]byte) (int, error)
}

type File struct{}

// File реализует метод Write, поэтому удовлетворяет интерфейсу Writer.
func (f *File) Write(data []byte) (int, error) {
    // ... логика записи
    return len(data), nil
}

// Статическая проверка: компилятор выдаст ошибку, если *File не реализует Writer.
// Используется пустой идентификатор _, чтобы переменная не была "неиспользованной".
var _ Writer = (*File)(nil)

func main() {}

2. Динамическая проверка (во время выполнения)

Этот способ используется, когда у вас есть переменная типа interface{} и нужно проверить, можно ли её привести к конкретному типу интерфейса. Для этого используется type assertion.

package main

import "fmt"

type Greeter interface {
    Greet()
}

type User struct{}

func (u User) Greet() {
    fmt.Println("Hello!")
}

func process(v interface{}) {
    // Проверяем, удовлетворяет ли значение в 'v' интерфейсу Greeter
    if greeter, ok := v.(Greeter); ok {
        fmt.Println("Тип удовлетворяет интерфейсу Greeter.")
        greeter.Greet() // Можно безопасно вызвать метод
    } else {
        fmt.Println("Тип НЕ удовлетворяет интерфейсу Greeter.")
    }
}

func main() {
    process(User{})
    process("some string")
}