go extension-methods

¿Cómo agregar nuevos métodos a un tipo existente en go?



extension-methods (2)

Como menciona el compilador, no puede extender los tipos existentes en otro paquete. Puede definir su propio alias o subpaquete de la siguiente manera:

type MyRouter mux.Router func (m *MyRouter) F() { ... }

o incrustando el enrutador original:

type MyRouter struct { *mux.Router } func (m *MyRouter) F() { ... } ... r := &MyRouter{router} r.F()

Deseo agregar un método de utilidad de conveniencia a los tipos de ruta y enrutador de gorila / mux:

package util import( "net/http" "github.com/0xor1/gorillaseed/src/server/lib/mux" ) func (r *mux.Route) Subroute(tpl string, h http.Handler) *mux.Route{ return r.PathPrefix("/" + tpl).Subrouter().PathPrefix("/").Handler(h) } func (r *mux.Router) Subroute(tpl string, h http.Handler) *mux.Route{ return r.PathPrefix("/" + tpl).Subrouter().PathPrefix("/").Handler(h) }

pero el compilador me informa

No se pueden definir nuevos métodos en mux.Router de tipo no local

Entonces, ¿cómo podría lograr esto? ¿Creo un nuevo tipo de estructura que tenga un mux anónimo.Ruta y campos mux.Router? ¿O algo mas?


Quería ampliar la respuesta dada por @jimt here . Esa respuesta es correcta y me ayudó enormemente a resolver esto. Sin embargo, hay algunas advertencias para ambos métodos (alias, incrustación) con los que tuve problemas.

nota : uso los términos padre e hijo, aunque no estoy seguro de que sea el mejor para la composición. Básicamente, parent es el tipo que desea modificar localmente. Child es el nuevo tipo que intenta implementar esa modificación.

Método 1 - Alias

type child parent // or type MyThing imported.Thing

  • Proporciona acceso a los campos.
  • No proporciona acceso a los métodos.

Método 2 - Incrustación ( documentación oficial )

type child struct { parent } // or with import and pointer type MyThing struct { *imported.Thing }

  • Proporciona acceso a los campos.
  • Proporciona acceso a los métodos.
  • Consideración requerida para la inicialización.

Resumen

  • Al usar el método de composición, el elemento primario incrustado no se inicializará si se trata de un puntero. El padre debe inicializarse por separado.
  • Si el elemento primario incrustado es un puntero y no se inicializa cuando se inicializa el elemento secundario, se producirá un error de eliminación de referencias del puntero.
  • Tanto los casos de alias como los incrustados proporcionan acceso a los campos del padre.
  • El alias no permite el acceso a los métodos de los padres, pero la incrustación del padre sí lo hace.

Puedes ver esto en el siguiente código.

ejemplo de trabajo en el patio de recreo

package main import ( "fmt" ) type parent struct { attr string } type childAlias parent type childObjParent struct { parent } type childPointerParent struct { *parent } func (p *parent) parentDo(s string) { fmt.Println(s) } func (c *childAlias) childAliasDo(s string) { fmt.Println(s) } func (c *childObjParent) childObjParentDo(s string) { fmt.Println(s) } func (c *childPointerParent) childPointerParentDo(s string) { fmt.Println(s) } func main() { p := &parent{"pAttr"} c1 := &childAlias{"cAliasAttr"} c2 := &childObjParent{} // When the parent is a pointer it must be initialized. // Otherwise, we get a nil pointer error when trying to set the attr. c3 := &childPointerParent{} c4 := &childPointerParent{&parent{}} c2.attr = "cObjParentAttr" // c3.attr = "cPointerParentAttr" // NOGO nil pointer dereference c4.attr = "cPointerParentAttr" // CAN do because we inherit parent''s fields fmt.Println(p.attr) fmt.Println(c1.attr) fmt.Println(c2.attr) fmt.Println(c4.attr) p.parentDo("called parentDo on parent") c1.childAliasDo("called childAliasDo on ChildAlias") c2.childObjParentDo("called childObjParentDo on ChildObjParent") c3.childPointerParentDo("called childPointerParentDo on ChildPointerParent") c4.childPointerParentDo("called childPointerParentDo on ChildPointerParent") // CANNOT do because we don''t inherit parent''s methods // c1.parentDo("called parentDo on childAlias") // NOGO c1.parentDo undefined // CAN do because we inherit the parent''s methods c2.parentDo("called parentDo on childObjParent") c3.parentDo("called parentDo on childPointerParent") c4.parentDo("called parentDo on childPointerParent") }