Интерфейс реализации функции

Я хочу знать, что здесь происходит.

Существует интерфейс для обработчика http:

type Handler interface {
    ServeHTTP(*Conn, *Request)
}

Эта реализация, я думаю, я понимаю.

type Counter int

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    fmt.Fprintf(c, "counter = %d\n", ctr);
    ctr++;
}

По моему мнению, тип "Counter" реализует интерфейс, так как он имеет метод, который имеет требуемую подпись. Все идет нормально. Затем дается следующий пример:

func notFound(c *Conn, req *Request) {
    c.SetHeader("Content-Type", "text/plain;", "charset=utf-8");
    c.WriteHeader(StatusNotFound);
    c.WriteString("404 page not found\n");
}

// Now we define a type to implement ServeHTTP:
type HandlerFunc func(*Conn, *Request)
func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
    f(c, req) // the receiver a func; call it
}
// Convert function to attach method, implement the interface:
var Handle404 = HandlerFunc(notFound);

Может ли кто-нибудь выяснить, почему и как эти различные функции подходят друг другу?

Ответ 1

Это:

type Handler interface {
    ServeHTTP(*Conn, *Request)
}

говорит, что любой тип, который удовлетворяет интерфейсу Handler, должен иметь метод ServeHTTP. Вышеупомянутое будет внутри пакета http.

type Counter int

func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
    fmt.Fprintf(c, "counter = %d\n", ctr);
    ctr++;
}

Это ставит метод в тип Counter, который соответствует ServeHTTP. Это пример, который отличается от следующего.

По моему мнению, тип "Счетчик" реализует интерфейс, поскольку он имеет метод, который имеет требуемую подпись.

Это правильно.

Следующая функция сама по себе не будет работать как Handler:

func notFound(c *Conn, req *Request) {
    c.SetHeader("Content-Type", "text/plain;", "charset=utf-8");
    c.WriteHeader(StatusNotFound);
    c.WriteString("404 page not found\n");
}

Остальная часть этого материала просто подгоняется выше, так что это может быть Handler.

В следующем случае HandlerFunc - это функция, которая принимает два аргумента, указатель на Conn и указатель на Request, и ничего не возвращает. Другими словами, любая функция, которая принимает эти аргументы и ничего не возвращает, может быть HandlerFunc.

// Now we define a type to implement ServeHTTP:
type HandlerFunc func(*Conn, *Request)

Здесь ServeHTTP - это метод, добавленный к типу HandlerFunc:

func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
    f(c, req) // the receiver a func; call it
}

Все, что он делает, это вызов самой функции (f) с указанными аргументами.

// Convert function to attach method, implement the interface:
var Handle404 = HandlerFunc(notFound);

В приведенной выше строке notFound был включен в качестве допустимого для интерфейса для Handler путем искусственного создания экземпляра типа из самой функции и превращения функции в метод ServeHTTP для экземпляра. Теперь Handle404 можно использовать с интерфейсом Handler. Это в основном своего рода трюк.

Ответ 2

Что именно вы не понимаете во второй половине? Это та же картина, что и выше. Вместо того, чтобы определять тип Counter как int, они определяют функцию, называемую notFound. Затем они создают тип функции HandlerFunc, который принимает два параметра, соединение и запрос. Затем они создают новый метод ServeHTTP, который привязывается к типу HandlerFunc. Handle404 - это просто экземпляр этого класса, который использует функцию notFound.