কীভাবে কোনও বিদ্যমান ধরণের নতুন পদ্ধতি যুক্ত করবেন?


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. রুট এবং mux. রাউটার ক্ষেত্র রয়েছে? অথবা অন্য কিছু?


মজার বিষয় হল এক্সটেনশন পদ্ধতিগুলিকে “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তবে আপনি কী আপনার নতুন পদ্ধতিগুলি ব্যবহার করতে চান?
ডোকাট

প্রথম সমাধানটি কীভাবে ব্যবহার করবেন? মাইআউটার (রাউটার)
tfzxyinhao

এম্বেডিং ব্যবহার করতে কিছুটা বেশি ব্যবহারিক বলে মনে হচ্ছে।
ivanjovanovic

124

আমি এখানে @ জিম্টের দেওয়া উত্তরে প্রসারিত করতে চেয়েছি । এই উত্তরটি সঠিক এবং এটিকে বাছাই করতে আমাকে ব্যাপকভাবে সহায়তা করেছে। যাইহোক, উভয় পদ্ধতিতে (ক্যান্সার্স (ওরফে, এম্বেড) কিছু ক্যাভেট রয়েছে যা দিয়ে আমার সমস্যা হয়েছিল।

দ্রষ্টব্য : আমি অভিভাবক এবং সন্তানের পদটি ব্যবহার করি, যদিও আমি নিশ্চিত নই যে এটি রচনার জন্য সেরা। মূলত, প্যারেন্ট হ'ল টাইপ যা আপনি স্থানীয়ভাবে সংশোধন করতে চান। শিশুটি নতুন ধরণের যা সেই পরিবর্তনটি বাস্তবায়নের চেষ্টা করে।

পদ্ধতি 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")
}

আপনার পোষ্টটি প্রতিটি প্রযুক্তিবিদ্যার সাথে পয়েন্ট করে তুলনা করার প্রচুর গবেষণা এবং প্রচেষ্টা দেখানোর জন্য অনেক সহায়ক very আমাকে প্রদত্ত ইন্টারফেসে রূপান্তর করার ক্ষেত্রে কী ঘটেছিল তা ভাবতে উত্সাহিত করার অনুমতি দিন। মানে, যদি আপনার কোনও কাঠামো থাকে এবং আপনি সেই কাঠামোটি চান (একটি তৃতীয় পক্ষের বিক্রেতা থেকে ধরা যাক) আপনি কোনও প্রদত্ত ইন্টারফেসের সাথে খাপ খাইয়ে নিতে চান, তবে আপনি এটি পেতে কে পরিচালনা করেন? আপনি টাইপ ওরফে নিয়োগ করতে পারেন বা এর জন্য এম্বেড টাইপ করতে পারেন।
ভিক্টর

@ ভিক্টর আমি আপনার প্রশ্ন অনুসরণ করি না, তবে আমি মনে করি যে আপনি কোনও কাঠামো কীভাবে পাবেন কীভাবে আপনি কোনও প্রদত্ত ইন্টারফেস সন্তুষ্ট করতে নিয়ন্ত্রণ করেন না। সংক্ষিপ্ত উত্তর, আপনি সেই কোডবেসে অবদান রেখে ছাড়া করবেন না। তবে, এই পোস্টে উপাদান ব্যবহার করে, আপনি প্রথম থেকে অন্য স্ট্রাক তৈরি করতে পারেন, তারপরে সেই স্ট্রাক্টটিতে ইন্টারফেসটি প্রয়োগ করতে পারেন। খেলার মাঠের এই উদাহরণটি দেখুন
TheHerk

হাই @ দ্য হের্ক, আমার লক্ষ্য হ'ল অন্য প্যাকেজ থেকে কাঠামোকে "প্রসারিত করার" সময় আপনি অন্য একটি পার্থক্য চিহ্নিত করুন। আমার কাছে দেখে মনে হচ্ছে, এর্কেভ করার দুটি উপায় আছে, টাইপ ওরফে (আপনার উদাহরণ) ব্যবহার করে এবং এম্বেড টাইপ ( play.golang.org/p/psejeXYbz5T ) ব্যবহার করে । আমার কাছে দেখে মনে হচ্ছে যে এই ধরণের উপন্যাসটি রূপান্তরকে আরও সহজ করে তোলে কারণ আপনার কেবল টাইপ রূপান্তর প্রয়োজন , আপনি যদি টাইপ মোড়কে ব্যবহার করেন তবে আপনাকে কোনও পয়েন্ট ব্যবহার করে "প্যারেন্ট" কাঠামোর রেফারেন্স দিতে হবে, সুতরাং, প্যারেন্ট টাইপটি নিজেই অ্যাক্সেস করতে হবে। আমার অনুমান ক্লায়েন্টের কোড পর্যন্ত ...
ভিক্টর

দয়া করে এখানে এই বিষয়টির অনুপ্রেরণা দেখুন stackoverflow.com/a/28800807/903998 , মন্তব্যগুলি অনুসরণ করুন এবং আমি আশা করি আপনি আমার
ভিক্টর

আমি আশা করি আমি আপনার অর্থটি অনুসরণ করতে পারতাম তবে আমার এখনও সমস্যা হচ্ছে। যার উত্তরে আমরা এই মন্তব্যগুলি লিখছি, আমি প্রতিটিটির সুবিধা এবং অসুবিধাগুলি সহ এম্বেডিং এবং এলিয়াসিং উভয়ই ব্যাখ্যা করি। আমি একজনের পক্ষে অন্যের পক্ষে কথা বলছি না। এটি হতে পারে যে আপনি পরামর্শ দিচ্ছেন যে আমি সেইসব উপকার বা কনস থেকে বাদ পড়েছি।
দ্য হের্ক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.