"<টাইপ> ইন্টারফেসের দিকে নির্দেশক, ইন্টারফেস নয়" বিভ্রান্তি


117

প্রিয় সহকর্মী বিকাশকারীগণ,

আমি এই সমস্যাটি পেয়েছি যা আমার কাছে কিছুটা অদ্ভুত বলে মনে হচ্ছে। কোডের এই স্নিপেটটি একবার দেখুন:

package coreinterfaces

type FilterInterface interface {
    Filter(s *string) bool
}

type FieldFilter struct {
    Key string
    Val string
}

func (ff *FieldFilter) Filter(s *string) bool {
    // Some code
}

type FilterMapInterface interface {
    AddFilter(f *FilterInterface) uuid.UUID     
    RemoveFilter(i uuid.UUID)                   
    GetFilterByID(i uuid.UUID) *FilterInterface
}

type FilterMap struct {
    mutex   sync.Mutex
    Filters map[uuid.UUID]FilterInterface
}

func (fp *FilterMap) AddFilter(f *FilterInterface) uuid.UUID {
    // Some code
}

func (fp *FilterMap) RemoveFilter(i uuid.UUID) {
    // Some code
}

func (fp *FilterMap) GetFilterByID(i uuid.UUID) *FilterInterface {
    // Some code
}

অন্য কিছু প্যাকেজে আমার কাছে নিম্নলিখিত কোড রয়েছে:

func DoFilter() {
    fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
    filtermap := &coreinterfaces.FilterMap{}
    _ = filtermap.AddFilter(fieldfilter) // <--- Exception is raised here
}

রান-টাইম উল্লেখ করা লাইনটি গ্রহণ করবে না কারণ

"ফিল্ডিল্ট ফিল্ডিল্টার (টাইপ * কোরিনেটারফেসস.ফিল্ডফিল্টার) টাইপ * কোরিনেটারফেসগুলি ব্যবহার করতে পারবেন না। ফিল্ডিন্টের যুক্তিতে ফিল্টারইন্টারফেস। অ্যাডফিল্টার: * কোরিনেটারফেসস। ফিল্টারইন্টারফেস ইন্টারফেসের জন্য নির্দেশক নয়,"

যাইহোক, কোডটি পরিবর্তন করার সময়:

func DoBid() error {
    bs := string(b)
    var ifilterfield coreinterfaces.FilterInterface
    fieldfilter := &coreinterfaces.FieldFilter{Key: "app", Val: "152511"}
    ifilterfield = fieldfilter
    filtermap := &coreinterfaces.FilterMap{}
    _ = filtermap.AddFilter(&ifilterfield)
}

সবকিছু ঠিক আছে এবং অ্যাপ্লিকেশনটি ডিবাগ করার সময় এটি সত্যিই অন্তর্ভুক্ত বলে মনে হয়

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


যখন পরিবর্তন * FilterInterfaceকরার জন্য FilterInterfaceলাইন _ = filtermap.AddFilter(fieldfilter)এখন উত্থাপন এই: filtermap.AddFilter করার যুক্তি fieldfilter ব্যবহার করতে পারে না (টাইপ coreinterfaces.FieldFilter) টাইপ coreinterfaces.FilterInterface হিসাবে: coreinterfaces.FieldFilter coreinterfaces.FilterInterface বাস্তবায়ন না (ফিল্টার পদ্ধতি পয়েন্টার রিসিভার আছে) তবে যখন পরিবর্তন _ = filtermap.AddFilter(&fieldfilter)এটি লাইন কাজ করে। এখানে কি হয়? এটা কেন?
0rka

4
কারণ যে পদ্ধতিগুলি ইন্টারফেস বাস্তবায়ন করে তাদের পয়েন্টার রিসিভার থাকে। একটি মান পাস করা, এটি ইন্টারফেস প্রয়োগ করে না; একটি পয়েন্টার পাস করে, এটি করে, কারণ পদ্ধতিগুলি তখন প্রয়োগ হয়। সাধারণভাবে বলতে গেলে, ইন্টারফেসের সাথে কাজ করার সময়, আপনি কোনও ইন্টারফেসের প্রত্যাশা করে এমন কোনও ফাংশনটির কাছে একটি পয়েন্টারটি পাস করেন। আপনি প্রায় কোনও পরিস্থিতিতে কোনও ইন্টারফেসের পয়েন্টার চান না।
অ্যাড্রিয়ান

4
আমি আপনার বক্তব্যটি বুঝতে পারি, তবে পরামিতিটির মানটি এমন * FilterInterfaceস্ট্রাক্ট থেকে পরিবর্তিত করে যা এই ইন্টারফেসটি প্রয়োগ করে, এটি ইন্টারফেসগুলি ফাংশনে পাস করার ধারণাটিকে ভেঙে দেয়। আমি যেটি সম্পাদন করতে চেয়েছিলাম তা আমি কী স্ট্রাকচারের মধ্য দিয়ে যাচ্ছি সেটির সাথে আবদ্ধ নয়, বরং এমন কোনও কাঠামো যা ইন্টারফেসটি আমি ব্যবহার করতে আগ্রহী তা প্রয়োগ করে। আপনি যে কোনও কোড পরিবর্তন করতে পারেন তা আমার পক্ষে আরও কার্যকর বা মানদণ্ডের হতে পারে বলে মনে হয়? আমি কিছু কোড পর্যালোচনা পরিষেবা ব্যবহার করে খুশি হব :)
0rka

4
আপনার ফাংশনটি একটি ইন্টারফেস যুক্তি (ইন্টারফেসের দিকে নির্দেশক নয়) গ্রহণ করা উচিত। কলারটিকে একটি স্ট্রাক্টের কাছে পয়েন্টার দিয়ে যেতে হবে যা ইন্টারফেস প্রয়োগ করে। এটি "ক্রিয়াকলাপগুলিতে ইন্টারফেসগুলি পাস করার ধারণাটি ভাঙবে না" - ফাংশনটি এখনও একটি ইন্টারফেস নেয়, আপনি ইন্টারফেস প্রয়োগ করে এমন একটি সংক্ষেপে যাচ্ছেন।
অ্যাড্রিয়ান

উত্তর:


157

সুতরাং আপনি এখানে দুটি ধারণাকে বিভ্রান্ত করছেন। কাঠামোর একটি পয়েন্টার এবং ইন্টারফেসের পয়েন্টার এক নয় not একটি ইন্টারফেস একটি স্ট্রাক্ট সরাসরি স্ট্রাক্ট বা স্ট্রকের পয়েন্টার সঞ্চয় করতে পারে। পরবর্তী ক্ষেত্রে, আপনি এখনও কেবল ইন্টারফেসটি সরাসরি ইন্টারফেসটি ব্যবহার করেন, ইন্টারফেসের কোনও পয়েন্টার নয় । উদাহরণ স্বরূপ:

type Fooer interface {
    Dummy()
}

type Foo struct{}

func (f Foo) Dummy() {}

func main() {
    var f1 Foo
    var f2 *Foo = &Foo{}

    DoFoo(f1)
    DoFoo(f2)
}

func DoFoo(f Fooer) {
    fmt.Printf("[%T] %+v\n", f, f)
}

আউটপুট:

[main.Foo] {}
[*main.Foo] &{}

https://play.golang.org/p/I7H_pv5H3Xl

উভয় ক্ষেত্রেই fভেরিয়েবলটি DoFooকেবল একটি ইন্টারফেস, কোনও ইন্টারফেসের পয়েন্টার নয় । যাইহোক, সংরক্ষণ করার সময় f2, ইন্টারফেসটি একটি কাঠামোর জন্য একটি পয়েন্টার ধারণ করেFoo

ইন্টারফেসের পয়েন্টারগুলি প্রায় কখনই কার্যকর হয় না । প্রকৃতপক্ষে, গো রানটাইমটি বিশেষভাবে কয়েকটি সংস্করণ পরিবর্তিত হয়ে স্বয়ংক্রিয়ভাবে ইন্টারফেস পয়েন্টারগুলি (যেমন এটি স্ট্রাকচার পয়েন্টারগুলির মতো করে) ব্যবহার করে নিরুৎসাহিত করে to অপ্রতিরোধ্য বেশিরভাগ ক্ষেত্রে, ইন্টারফেসের পয়েন্টারটি ইন্টারফেসগুলি কীভাবে কাজ করবে বলে বোঝা যায় তার একটি ভুল বোঝাবুঝির প্রতিফলন করে।

তবে ইন্টারফেসের ক্ষেত্রে সীমাবদ্ধতা রয়েছে। আপনি যদি কোনও কাঠামো সরাসরি একটি ইন্টারফেসে পাস করেন তবে কেবলমাত্র সেই ধরণের মান পদ্ধতিগুলি (যেমন func (f Foo) Dummy(), না func (f *Foo) Dummy()) ইন্টারফেসটি পূরণ করতে ব্যবহার করা যেতে পারে। এটি কারণ আপনি ইন্টারফেসে মূল কাঠামোর একটি অনুলিপি সংরক্ষণ করছেন, সুতরাং পয়েন্টার পদ্ধতিতে অপ্রত্যাশিত প্রভাব পড়বে (যেমন, মূল কাঠামোটি পরিবর্তন করতে অক্ষম)। সুতরাং থাম্বের ডিফল্ট নিয়মটি হল ইন্টারফেসগুলিতে স্ট্রাকচারের পয়েন্টারগুলি সংরক্ষণ করা , যদি না বাধ্যতামূলক কারণ না থাকে।

বিশেষত আপনার কোড সহ, আপনি যদি অ্যাডফিল্টার ফাংশন স্বাক্ষরটিকে এতে পরিবর্তন করেন:

func (fp *FilterMap) AddFilter(f FilterInterface) uuid.UUID

এবং এতে getFilterByID স্বাক্ষর:

func (fp *FilterMap) GetFilterByID(i uuid.UUID) FilterInterface

আপনার কোডটি প্রত্যাশার মতো কাজ করবে। fieldfilterধরণের *FieldFilter, যা FilterInterfaceইন্টারফেসের ধরণটি পূর্ণ করে তোলে এবং AddFilterএটি এটি গ্রহণ করবে।

পদ্ধতিতে, ধরণের এবং ইন্টারফেসগুলি কীভাবে কাজ করে এবং গোয়ে একে অপরের সাথে সংহত হয় তা বোঝার জন্য এখানে বেশ কয়েকটি ভাল রেফারেন্স রয়েছে:


"এটি কারণ আপনি ইন্টারফেসে মূল কাঠামোর একটি অনুলিপি সংরক্ষণ করছেন, সুতরাং পয়েন্টার পদ্ধতিতে অপ্রত্যাশিত প্রভাব পড়বে (যেমন, মূল কাঠামোটি পরিবর্তন করতে অক্ষম)" - এটি সীমাবদ্ধতার কারণ হিসাবে বোধ করে না। সর্বোপরি, একমাত্র অনুলিপি ইন্টারফেসে সমস্ত পাশাপাশি সঞ্চিত থাকতে পারে।
WPWoodJr

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

5
GetFilterByID(i uuid.UUID) *FilterInterface

যখন আমি এই ত্রুটিটি পাই তখন সাধারণত এটি হয় কারণ আমি কোনও ইন্টারফেসের পরিবর্তে একটি ইন্টারফেসের জন্য একটি পয়েন্টার নির্দিষ্ট করছি (এটি আসলে আমার কাঠামোর জন্য একটি পয়েন্টার যা ইন্টারফেসটি পূরণ করে)।

* ইন্টারফেস {... for এর জন্য একটি বৈধ ব্যবহার রয়েছে তবে আরও সাধারণভাবে আমি ভাবছি 'এটি একটি পয়েন্টার' এর পরিবর্তে 'এটি একটি ইন্টারফেস যা আমি লিখছি কোডটির পয়েন্টার হিসাবে ঘটবে'

কেবল এটি এখান থেকে ছুঁড়ে ফেলা হয়েছে কারণ গ্রহণযোগ্য উত্তর যদিও বিস্তারিত থাকলেও আমাকে সমস্যা সমাধানে সহায়তা করে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.