Пожалуйста, указывайте источник при перепечатке оригинальной статьи
последнее чтениеMartini
исходный код, читайтеinject
эта часть,inject
существуетMartini
вездесущ в коде,Martini
Абсолютное ядро фреймворка.
Сначала посмотрите на объявление типа инжектора:
type injector struct {
values map[reflect.Type]reflect.Value
parent Injector
}
отложить в сторонуparent
не вижу,values
это таблица сопоставления, используемая для сохранения введенных параметров, этоreflect.Type
когда ключ,reflect.Value
представляет собой карту ценностей.
parent Injector
Какого черта?
// Injector represents an interface for mapping and injecting dependencies into structs
// and function arguments.
type Injector interface {
Applicator
Invoker
TypeMapper
// SetParent sets the parent of the injector. If the injector cannot find a
// dependency in its Type map it will check its parent before returning an
// error.
SetParent(Injector)
}
// Applicator represents an interface for mapping dependencies to a struct.
type Applicator interface {
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'. Returns an error if the injection
// fails.
Apply(interface{}) error
}
// Invoker represents an interface for calling functions via reflection.
type Invoker interface {
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type. Returns
// a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke(interface{}) ([]reflect.Value, error)
}
// TypeMapper represents an interface for mapping interface{} values based on type.
type TypeMapper interface {
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
Map(interface{}) TypeMapper
// Maps the interface{} value based on the pointer of an Interface provided.
// This is really only useful for mapping a value as an interface, as interfaces
// cannot at this time be referenced directly without a pointer.
MapTo(interface{}, interface{}) TypeMapper
// Provides a possibility to directly insert a mapping based on type and value.
// This makes it possible to directly map type arguments not possible to instantiate
// with reflect like unidirectional channels.
Set(reflect.Type, reflect.Value) TypeMapper
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
// the Type has not been mapped.
Get(reflect.Type) reflect.Value
}
Injector представляет собой комбинацию объявлений интерфейса инъекции. Сначала мы сосредоточимся на интерфейсе TypeMapper. Из исходного кода мы можем знать, что Map и MapTo используются для сопоставления типов данных и данных сvalues map[reflect.Type]reflect.Value
Методы.
Метод Map относительно прост и использует отражение для получения типа объекта.
func (i *injector) Map(val interface{}) TypeMapper {
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
return i
}
Теперь предположим, что когда в параметре несколько строк,values map[reflect.Type]reflect.Value
Эта карта сохранит только отображение последней строки, так что же нам делать с ней, чтобы полностью сохранить все строковые параметры?
рассмотреть возможностьinterface
Базовая реализация типа (тип, данные),inject
В библиотеке реализована функция получения типа из указателя на интерфейс.InterfaceOf
,а такжеMapTo
затем используйтеInterfaceOf
чтобы получить тип входящих данных.
func InterfaceOf(value interface{}) reflect.Type {
t := reflect.TypeOf(value)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Interface {
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
}
return t
}
func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
return i
}
Это гениальный ход, давайте найдем чужой пример:
package main
import (
"fmt"
"github.com/codegangsta/inject"
)
type SpecialString interface{}
func main() {
fmt.Println(inject.InterfaceOf((*interface{})(nil)))
fmt.Println(inject.InterfaceOf((*SpecialString)(nil)))
}
выход
interface {}
main.SpecialString
видеть это? нулевой указатель на интерфейс, хотяdata
ноль, но мы просто хотим этогоtype
. Пошаговое объяснение:
//以(*SpecialString)(nil)为例
t := reflect.TypeOf(value) //t是*main.SpecialString,t.Kind()是ptr,t.Elem()是main.SpecialString
for t.Kind() == reflect.Ptr { //循环判断,也许是指向指针的指针
t = t.Elem() //Elem returns a type's element type.
}
if t.Kind() != reflect.Interface {
... //如果不是Interface类型,报panic
}
return t //返回(*SpecialString)(nil)的元素原始类型
interface{}
что вgo
вinterface{}
всемогущAny
.inject
Используя преимущества характеристик (*interface{})(nil), переносящих типы данных, для завершения передачи типов данных используется только нулевой указатель, а связывание одного и того же типа данных расширяется.
пойдемmartini.go
Давайте посмотрим, как работает эта инъекция.
// Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.
type Martini struct {
inject.Injector
handlers []Handler
action Handler
logger *log.Logger
}
// New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.
func New() *Martini {
m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)}
m.Map(m.logger)
m.Map(defaultReturnHandler())
return m
}
func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0}
c.SetParent(m)
c.MapTo(c, (*Context)(nil))
c.MapTo(c.rw, (*http.ResponseWriter)(nil))
c.Map(req)
return c
}
индивидуальныеMartini
Структура содержитinject.Injector
интерфейс, поэтому его можно легко ввестиlogger
. следовать заInvoke
При использовании промежуточного программного обеспечения вы, естественно, можете передатьInjector
изGet
способ получитьlogger
объект.context
Затем используйте метод MapTo для внедренияContext
а такжеhttp.ResponseWriter
Эти два типа интерфейса.
ТакInvoke
Как вы вызываете функцию и вводите параметры, когда это так? пожалуйста, переместите«Как Invoke динамически передает параметры»
Я Gugu Chicken, инженер полного стека, который все еще учится. Я люблю жизнь, я люблю бегать, и моя семья является движущей силой для меня, чтобы продолжать двигаться вперед.