Jak dodać nowe metody do istniejącego typu W go?

Chcę dodać wygodną metodę util do typów tras i routerów gorilla/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)
}

Ale kompilator informuje mnie

Nie można zdefiniować nowych metod na nielokalnym typie mux.Router

Jak mam to osiągnąć? Czy mogę utworzyć nowy typ struktury, który ma anonimowy mux.Trasa i mux.Pola routera? Albo coś innego?
Author: Chris Martin, 2015-03-02

2 answers

Jak wspomina kompilator, nie można rozszerzyć istniejących typów w innym pakiecie. Możesz zdefiniować własny alias lub podpakiet w następujący sposób:

type MyRouter mux.Router

func (m *MyRouter) F() { ... }

Lub przez osadzenie oryginalnego routera:

type MyRouter struct {
    *mux.Router
}

func (m *MyRouter) F() { ... }

...
r := &MyRouter{router}
r.F()
 104
Author: jimt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 00:02:02

Chciałem rozwinąć odpowiedź udzieloną przez @ jimt tutaj . Ta odpowiedź jest poprawna i pomogła mi ogromnie w uporządkowaniu tego. Istnieją jednak pewne zastrzeżenia do obu metod (alias, embed), z którymi miałem problemy.

Uwaga : używam terminów rodzic i dziecko, choć nie jestem pewien, czy jest to najlepsze dla kompozycji. Zasadniczo rodzic to typ, który chcesz zmodyfikować lokalnie. Child jest nowym typem, który próbuje zaimplementować tę modyfikację.

Metoda 1 - Alias

type child parent
// or
type MyThing imported.Thing
  • zapewnia dostęp do pól.
  • nie zapewnia dostępu do metod.

Method 2 - Embedding (official documentation)

type child struct {
    parent
}
// or with import and pointer
type MyThing struct {
    *imported.Thing
}
  • zapewnia dostęp do pól.
  • zapewnia dostęp do metod.
  • wymagane rozważenie inicjalizacji.

Podsumowanie

  • używając metody kompozycji osadzony rodzic nie zainicjalizuje się, jeśli jest wskaźnikiem. Rodzic musi być zainicjowany oddzielnie.
  • Jeśli osadzony rodzic jest wskaźnikiem i nie jest inicjowany podczas inicjalizacji potomka, wystąpi błąd dereferencji wskaźnika zerowego.
  • zarówno przypadki aliasów, jak i osadzania zapewniają dostęp do pól rodzica.
  • alias nie zezwala na dostęp do metod rodzica, ale osadzanie rodzica tak.

Możesz to zobaczyć w poniższym kodzie.

Przykład pracy na placu zabaw

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")
}
 53
Author: TheHerk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:27