गो में मौजूदा प्रकार में नए तरीके कैसे जोड़ें?


129

मैं 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)
}

लेकिन संकलक ने मुझे सूचित किया

गैर-स्थानीय प्रकार mux.Router पर नए तरीकों को परिभाषित नहीं कर सकता

तो मैं इसे कैसे प्राप्त करूंगा? क्या मैं एक नया संरचना प्रकार बनाता हूं जिसमें एक अनाम mux है। Route और mux.Router फ़ील्ड्स? या कुछ और?


दिलचस्प रूप से विस्तार के तरीकों को “extension methods are not object-oriented”सी # के लिए गैर-वस्तु-उन्मुख ( ) के रूप में माना जाता है, लेकिन जब आज उन्हें देखते हैं, तो मुझे तुरंत गो के इंटरफेस (और ऑब्जेक्ट ओरिएंटेशन पर पुनर्विचार करने के लिए इसका दृष्टिकोण) याद किया गया था, और फिर मेरे पास यह बहुत सवाल था।
वुल्फ

जवाबों:


173

संकलक के रूप में, आप किसी अन्य पैकेज में मौजूदा प्रकार का विस्तार नहीं कर सकते। आप अपने स्वयं के उपनाम या उप-पैकेज को निम्नानुसार परिभाषित कर सकते हैं:

type MyRouter mux.Router

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

या मूल राउटर को एम्बेड करके:

type MyRouter struct {
    *mux.Router
}

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

...
r := &MyRouter{router}
r.F()

10
या सिर्फ एक फ़ंक्शन का उपयोग करें ...?
पॉल हैंकिन

5
@Paul यह कर स्ट्रिंग () और MarshalJSON () की तरह ओवरराइड कार्यों के लिए आवश्यक है
Riking

31
यदि आप पहला भाग करते हैं, तो आप mux.Routerउदाहरणों को किस तरह से जोड़ते हैं MyRouter? उदाहरण के लिए यदि आपके पास एक पुस्तकालय है जो लौटता है mux.Routerलेकिन आप अपने नए तरीकों का उपयोग करना चाहते हैं?
docwhat

पहले समाधान का उपयोग कैसे करें? MyRouter (राउटर)
tfzxyinhao

एम्बेडिंग उपयोग करने के लिए थोड़ा अधिक व्यावहारिक लगता है।
ivanjovanovic

124

मैं यहाँ @jimt द्वारा दिए गए उत्तर पर विस्तार करना चाहता था । यह उत्तर सही है और मुझे इसे हल करने में काफी मदद मिली। हालांकि, दोनों तरीकों (उपनाम, एम्बेड) के लिए कुछ चेतावनी हैं, जिनके साथ मुझे परेशानी थी।

ध्यान दें : मैं शब्दों का उपयोग करता हूं अभिभावक और बच्चे, हालांकि मुझे यकीन नहीं है कि यह रचना के लिए सबसे अच्छा है। मूल रूप से, माता-पिता वह प्रकार है जिसे आप स्थानीय स्तर पर संशोधित करना चाहते हैं। बाल नया प्रकार है जो उस संशोधन को लागू करने का प्रयास करता है।

विधि 1 - प्रकार परिभाषा

type child parent
// or
type MyThing imported.Thing
  • खेतों तक पहुँच प्रदान करता है।
  • विधियों तक पहुँच प्रदान नहीं करता है।

विधि 2 - एंबेडिंग ( आधिकारिक दस्तावेज )

type child struct {
    parent
}
// or with import and pointer
type MyThing struct {
    *imported.Thing
}
  • खेतों तक पहुँच प्रदान करता है।
  • विधियों तक पहुँच प्रदान करता है।
  • आरंभीकरण के लिए विचार की आवश्यकता है।

सारांश

  • रचना पद्धति का उपयोग करते हुए एम्बेडेड अभिभावक एक सूचक होने पर इसे इनिशियलाइज़ नहीं करेगा। अभिभावक को अलग से आरंभीकृत किया जाना चाहिए।
  • यदि एम्बेडेड अभिभावक एक पॉइंटर है और जब बच्चे को इनिशियलाइज़ किया जाता है तो उसे इनिशियलाइज़ नहीं किया जाता है, एक निल पॉइंटर डेरेफेरेंस एरर आएगा।
  • दोनों प्रकार की परिभाषा और एम्बेड मामले माता-पिता के क्षेत्रों तक पहुंच प्रदान करते हैं।
  • प्रकार की परिभाषा माता-पिता के तरीकों तक पहुंच की अनुमति नहीं देती है, लेकिन माता-पिता को एम्बेड करती है।

आप इसे निम्न कोड में देख सकते हैं।

खेल के मैदान पर काम करने का उदाहरण

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")
}

आपकी पोस्ट बहुत उपयोगी है क्योंकि बहुत से शोध और प्रयास प्रत्येक बिंदु को बिंदु से तुलना करने की कोशिश कर रहे हैं .. मुझे आपको यह सोचने के लिए प्रोत्साहित करने की अनुमति देता है कि किसी दिए गए इंटरफ़ेस में रूपांतरण के मामले में क्या होता है। मेरा मतलब है, अगर आपके पास एक संरचना है और आप चाहते हैं कि संरचना (किसी तीसरे पक्ष के विक्रेता से मान लें) आप किसी दिए गए इंटरफ़ेस के अनुकूल होना चाहते हैं, तो आप इसे प्राप्त करने के लिए किसे प्रबंधित करते हैं? आप इसके लिए अन्य उपनाम टाइप कर सकते हैं या एम्बेड कर सकते हैं।
विक्टर

@ निर्णयकर्ता मैं आपके प्रश्न का पालन नहीं करता, लेकिन मुझे लगता है कि आपका पूछना यह है कि एक ऐसी संरचना कैसे प्राप्त करें जिसे आप किसी दिए गए इंटरफ़ेस को संतुष्ट करने के लिए नियंत्रित नहीं करते हैं। लघु उत्तर, आप उस कोडबेस में योगदान के अलावा नहीं हैं। हालांकि, इस पोस्ट में सामग्री का उपयोग करके, आप पहले से एक और संरचना बना सकते हैं, फिर उस संरचना पर इंटरफ़ेस लागू कर सकते हैं। इस खेल के मैदान का उदाहरण देखें ।
हर्क

हाय @TheHerk, मुझे क्या उद्देश्य है कि आप एक और अंतर को इंगित करें जब एक पैकेज से एक संरचना का "विस्तार" किया जाए। मेरे जैसा दिखता है, कि टाइप करने के लिए दो तरीके हैं इस प्रकार, उपनाम (आपका उदाहरण) और प्रकार एम्बेड का उपयोग करके ( play.golang.org/p/psejeXYbz5T )। मेरे लिए यह दिखता है कि टाइप उर्फ ​​रूपांतरण को आसान बनाता है क्योंकि आपको केवल एक प्रकार के रूपांतरण की आवश्यकता होती है , यदि आप टाइप रैप का उपयोग करते हैं तो आपको एक डॉट का उपयोग करके "माता-पिता" संरचना को संदर्भित करने की आवश्यकता है, इस प्रकार, मूल प्रकार का उपयोग करके। मुझे लगता है कि ग्राहक कोड तक है ...
विक्टर

कृपया, इस विषय की प्रेरणा यहाँ देखें stackoverflow.com/a/28800807/903998 , टिप्पणियों का पालन करें और मुझे आशा है कि आप मेरी बात देखेंगे
विक्टर

काश मैं आपके अर्थ का पालन कर सकता, लेकिन मुझे अभी भी परेशानी हो रही है। जिस उत्तर पर हम ये टिप्पणियां लिख रहे हैं, उसके उत्तर में, मैं एम्बेडिंग और अलियासिंग दोनों को समझाता हूं, जिसमें प्रत्येक के फायदे और नुकसान भी शामिल हैं। मैं एक के लिए दूसरे की वकालत नहीं कर रहा हूँ। यह हो सकता है कि आपका सुझाव है कि मैं उन पेशेवरों या विपक्षों में से एक को याद कर रहा हूं।
TheHerk
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.