2009-11-21 3 views
10

Я хочу знать, что здесь происходит.Функциональный интерфейс реализации

Существует интерфейс для обработчика 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++; 
} 

От моего понимания, что тип «Счетчик» реализует интерфейс, поскольку он имеет метод, который имеет требуемую подпись. Все идет нормально. Затем дается следующий пример:

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's a func; call it 
} 
// Convert function to attach method, implement the interface: 
var Handle404 = HandlerFunc(notFound); 

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

ответ

12

Это:

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++; 
} 

Это ставит метод на тип счетчика, который соответствует 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's a func; call it 
} 

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

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

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

+0

Хорошо, я думаю, что я понял, что меня сбило с толку, это преобразование notFound в HandlerFunc. После перечитывания раздела конверсий эффективного перехода более ясно, как это может также относиться к функциям. http://golang.org/doc/effective_go.html#conversions – mbarkhau

1

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

+2

Да, это типичное функциональное программирование более высокого порядка. Это может сбивать с толку в первый раз, когда вы его видите, и прокладываете себе путь по этим типам. – Suppressingfire