এই সংকলন-সময় ত্রুটি দেখা দেয় যখন আপনি একটি কংক্রিট টাইপটিকে একটি ইন্টারফেসের ধরণে অ্যাসাইন বা পাস (বা রূপান্তর) করার চেষ্টা করেন ; এবং টাইপ নিজেই ইন্টারফেস প্রয়োগ করে না, টাইপটির কেবলমাত্র একটি পয়েন্টার ।
আসুন একটি উদাহরণ দেখুন:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
Stringerইন্টারফেস ধরনের শুধুমাত্র একটি পদ্ধতি রয়েছে: String()। একটি ইন্টারফেস মান সংরক্ষণ করা হয় যে কোনও মান Stringerএই পদ্ধতি থাকা আবশ্যক। আমরা একটিও তৈরি করেছি MyTypeএবং আমরা পয়েন্টার রিসিভার MyType.String()সহ একটি পদ্ধতি তৈরি করেছি । এর অর্থ মেথডটি টাইপের মেথড সেটে রয়েছে তবে এর মতো নয় ।String()*MyTypeMyType
যখন আমরা MyTypeপ্রকারের একটি ভেরিয়েবলের মান নির্ধারণের চেষ্টা করি তখন আমরা Stringerত্রুটিটি প্রশ্নে পেয়েছি:
m := MyType{value: "something"}
var s Stringer
s = m // cannot use m (type MyType) as type Stringer in assignment:
// MyType does not implement Stringer (String method has pointer receiver)
তবে আমরা যদি ধরণের একটি মান নির্ধারণের চেষ্টা করি তবে সবকিছু ঠিক *MyTypeআছে Stringer:
s = &m
fmt.Println(s)
এবং আমরা প্রত্যাশিত ফলাফল পেয়েছি ( গো খেলার মাঠে এটি চেষ্টা করুন ):
something
সুতরাং এই সংকলন-সময় ত্রুটি পাওয়ার প্রয়োজনীয়তা:
- অ-পয়েন্টার কংক্রিট ধরণের একটি মান নির্ধারিত (বা উত্তীর্ণ বা রূপান্তরিত)
- একটি ইন্টারফেস টাইপ বরাদ্দ করা হয়েছে (বা এতে রূপান্তরিত হয়েছে, বা রূপান্তরিত হয়েছে)
- কংক্রিটের ধরণের ইন্টারফেসের প্রয়োজনীয় পদ্ধতি রয়েছে তবে পয়েন্টার রিসিভার সহ
সমস্যা সমাধানের সম্ভাবনা:
- মানটির একটি পয়েন্টার অবশ্যই ব্যবহার করতে হবে, যার পদ্ধতি সেটটিতে পয়েন্টার রিসিভারের সাথে পদ্ধতিটি অন্তর্ভুক্ত থাকবে
- অথবা রিসিভারের ধরণটি অবশ্যই নন-পয়েন্টারটিতে পরিবর্তন করতে হবে , সুতরাং নন-পয়েন্টার কংক্রিটের পদ্ধতি সেটটিতেও পদ্ধতিটি থাকবে (এবং এইভাবে ইন্টারফেসটি সন্তুষ্ট করবে)। এটি কার্যকর বা নাও হতে পারে, যেমন পদ্ধতিটির মানটি সংশোধন করতে হয়, একটি পয়েন্টারবিহীন রিসিভার কোনও বিকল্প নয়।
স্ট্রাক্টস এবং এম্বেডিং
স্ট্রাক্টগুলি এবং এমবেডিং ব্যবহার করার সময় , প্রায়ই এটি "আপনি" হয় না যে কোনও ইন্টারফেস প্রয়োগ করে (একটি পদ্ধতি বাস্তবায়ন সরবরাহ করে), তবে আপনি নিজের মধ্যে এম্বেড করেন এমন একটি ধরন struct। এই উদাহরণে পছন্দ করুন:
type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
আবার, সংকলন-সময় ত্রুটি, কারণ পদ্ধতির সেটটিতে এমবেড MyType2থাকা String()পদ্ধতি থাকে না MyType, কেবলমাত্র সেই পদ্ধতির সেট থাকে *MyType2, সুতরাং নিম্নলিখিত কাজগুলি ( গো প্লেগ্রাউন্ডে এটি চেষ্টা করুন ):
var s Stringer
s = &m2
আমরা এম্বেড করে *MyTypeএবং কেবলমাত্র একটি অ-পয়েন্টার ব্যবহার করে MyType2( গো প্লেগ্রাউন্ডে এটি ব্যবহার করে দেখুন ): আমরা এটিকে কাজ করতেও পারি :
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
এছাড়াও, আমরা এম্বেড (যা হয় ) MyTypeবা যাই হোক না কেন *MyType, যদি আমরা পয়েন্টার ব্যবহার করি তবে *MyType2এটি সর্বদা কার্যকর হবে ( গো প্লেগ্রাউন্ডে চেষ্টা করুন ):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
বৈশিষ্ট থেকে প্রাসঙ্গিক বিভাগ (বিভাগ স্ট্রাক্ট প্রকার থেকে ):
একটি কাঠামোর ধরণ Sএবং নাম প্রকারের দেওয়া T, প্রচারিত পদ্ধতিগুলি নিম্নরূপে কাঠামোর পদ্ধতিতে অন্তর্ভুক্ত করা হয়েছে:
- যদি
Sকোনও বেনামি ক্ষেত্র থাকে Tতবে পদ্ধতির সেটগুলি Sএবং *Sউভয়ই রিসিভার সহ প্রচারিত পদ্ধতিগুলি অন্তর্ভুক্ত করে T। এর পদ্ধতির সেটটিতে *Sরিসিভার সহ প্রচারিত পদ্ধতিও অন্তর্ভুক্ত *T।
- যদি
Sএকটি বেনামী ক্ষেত্র রয়েছে *T, পদ্ধতি সেট Sএবং *Sউভয় উন্নীত রিসিভার পদ্ধতিগুলোর মধ্যে রয়েছে Tবা *T।
সুতরাং অন্য কথায়: যদি আমরা একটি অ-পয়েন্টার প্রকারটি এম্বেড করি তবে নন-পয়েন্টার এম্বেডারের পদ্ধতি সেটটি কেবলমাত্র পয়েন্টারবিহীন রিসিভারের (এম্বেডড টাইপ থেকে) প্রাপ্ত পদ্ধতিগুলি পায়।
যদি আমরা কোনও পয়েন্টার প্রকারটি এম্বেড করে থাকি তবে নন-পয়েন্টার এম্বেডারের পদ্ধতি সেট পয়েন্টার এবং নন-পয়েন্টার রিসিভার উভয়ই (এম্বেডড টাইপ থেকে) সহ পদ্ধতি পায়।
যদি আমরা এম্বেডারে একটি পয়েন্টার মান ব্যবহার করি তবে এম্বেড থাকা প্রকারটি পয়েন্টার কিনা তা নির্বিশেষে, এম্বেডারে পয়েন্টারের সেটটি সর্বদা পয়েন্টার এবং অ-পয়েন্টার রিসিভার উভয়ই (এম্বেডড টাইপ থেকে) উভয়ই পদ্ধতি পায়।
বিঃদ্রঃ:
একটি খুব অনুরূপ কেস আছে, যখন আপনার ইন্টারফেসের মান থাকে যা একটি মানকে জড়িয়ে দেয় MyTypeএবং আপনি এটি থেকে অন্য একটি ইন্টারফেস মান লিখতে চেষ্টা করেন Stringer,। এক্ষেত্রে উপরে বর্ণিত কারণগুলির জন্য দৃser়তা রাখা হবে না, তবে আমরা কিছুটা আলাদা রানটাইম-ত্রুটি পেয়েছি:
m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
রানটাইম আতঙ্ক ( গো খেলার মাঠে এটি চেষ্টা করে দেখুন ):
panic: interface conversion: main.MyType is not main.Stringer:
missing method String
টাইপ দাবির পরিবর্তে রূপান্তর করার চেষ্টা করা, আমরা যে সংকলন-সময় ত্রুটিটি নিয়ে কথা বলছি তা পেয়ে যাচ্ছি:
m := MyType{value: "something"}
fmt.Println(Stringer(m))
func (m *MyType)", বা কোনও নয় । তাই নাকি? আমি কি বিভিন্ন ধরণের "সদস্য ফাংশন" মিশ্রণ করতে পারি, যেমন,func (m *MyType)&func (m MyType)?