এক্স ওয়াই প্রয়োগ করে না (… পদ্ধতিতে পয়েন্টার রিসিভার রয়েছে) [বন্ধ]


201

ইতিমধ্যে এখানে বেশ কয়েকটি প্রশ্নোত্তর রয়েছে যেমন " এক্স ওয়াই ব্যবহার করে না (... পদ্ধতিতে পয়েন্টার রিসিভার রয়েছে) ", তবে আমার কাছে মনে হয় তারা বিভিন্ন জিনিস নিয়ে কথা বলছে, এবং আমার নির্দিষ্ট ক্ষেত্রে প্রয়োগ করছে না।

সুতরাং, প্রশ্নটিকে খুব সুনির্দিষ্ট করার পরিবর্তে, আমি এটিকে বিস্তৃত এবং বিমূর্ত বলছি - মনে হচ্ছে বেশ কয়েকটি বিভিন্ন ক্ষেত্রে রয়েছে যা এই ত্রুটি ঘটতে পারে, দয়া করে কেউ সংক্ষিপ্ত বিবরণ দিতে পারেন?

অর্থাৎ সমস্যাটি কীভাবে এড়ানো যায় এবং যদি এটি ঘটে থাকে তবে কী কী সম্ভাবনা রয়েছে? ধন্যবাদ.

উত্তর:


365

এই সংকলন-সময় ত্রুটি দেখা দেয় যখন আপনি একটি কংক্রিট টাইপটিকে একটি ইন্টারফেসের ধরণে অ্যাসাইন বা পাস (বা রূপান্তর) করার চেষ্টা করেন ; এবং টাইপ নিজেই ইন্টারফেস প্রয়োগ করে না, টাইপটির কেবলমাত্র একটি পয়েন্টার

আসুন একটি উদাহরণ দেখুন:

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)?
এক্সপিটি

3
@ xpt আপনি পয়েন্টার এবং নন-পয়েন্টার রিসিভারগুলিকে মিশ্রিত করতে পারেন, এটি সবগুলি তৈরি করার প্রয়োজন নেই। পয়েন্টার রিসিভার সহ যদি আপনার 19 টি পদ্ধতি থাকে এবং আপনি পয়েন্টারবিহীন রিসিভার দিয়ে একটি তৈরি করেন তবে এটি কেবল অদ্ভুত। আপনি যদি মিশ্রণ শুরু করেন তবে কোন পদ্ধতি কোন ধরণের পদ্ধতি সেটগুলির একটি অংশ তা ট্র্যাক করা আরও শক্ত করে তোলে। এই উত্তরে আরও বিশদ: গোলিংয়ের মান প্রাপ্তি বনাম পয়েন্টার রিসিভার?
আইকজা

"নোট:" এর শেষে বর্ণিত সমস্যাটিকে আপনি কীভাবে সমাধান করবেন {an একটি মানটি মোড়ানো একটি ইন্টারফেস সহ pping। MyType, যদি আপনি MyTypeমান পদ্ধতি ব্যবহার করতে পরিবর্তন করতে না পারেন । আমি এই জাতীয় কিছু চেষ্টা করেছি (&i).(*Stringer)কিন্তু এটি কাজ করছে না। এটা কি সম্ভব?
জোয়েল এডস্ট্রোম

1
@ জোয়েল এডস্ট্রোম হ্যাঁ, এটি সম্ভব, তবে এটি কিছুটা বোধগম্য নয়। উদাহরণস্বরূপ, আপনি নন-পয়েন্টার টাইপের মান টাইপ-চাপুন এবং এটি একটি ভেরিয়েবলের মধ্যে সঞ্চয় x := i.(MyType)করতে পারেন , উদাহরণস্বরূপ , এবং তারপরে আপনি পয়েন্টার রিসিভার সহ পদ্ধতিগুলি কল করতে পারেন, উদাহরণস্বরূপ i.String(), এটি একটি শর্টহ্যান্ড (&i).String()যার জন্য সফল হয় কারণ ভেরিয়েবলগুলি সম্বোধনযোগ্য। তবে মান পরিবর্তনের পয়েন্টার পদ্ধতিটি (পয়েন্টেড মান) ইন্টারফেসের মানটিতে আবৃত মানের মধ্যে প্রতিফলিত হবে না, এ কারণেই এটি সামান্য অর্থ দেয়।
আইজজা

1
@ ডিপনাটটিউ এর দুটি পদ্ধতি *Tপদ্ধতি সেটটিতে অন্তর্ভুক্ত নেই Sকারণ Sএটি ঠিকানাযোগ্য হতে পারে না (উদাহরণস্বরূপ ফাংশন রিটার্ন মান বা মানচিত্রের সূচকের ফলাফল), এবং কারণ কেবলমাত্র একটি অনুলিপি উপস্থিত / প্রাপ্ত হয় এবং যদি তার ঠিকানা গ্রহণের অনুমতি দেওয়া হয় তবে পদ্ধতিটি পয়েন্টার রিসিভার সহ কেবলমাত্র অনুলিপিটি সংশোধন করতে পারে (আপনি মনে করবেন যে মূলটি সংশোধন করা হয়েছে তাই বিভ্রান্তি)। উদাহরণস্বরূপ এই উত্তরটি দেখুন: প্রতিচ্ছবি সেটস্ট্রিং ব্যবহার করে
আইজজা

33

এটি সংক্ষিপ্ত রাখতে, যাক আপনার এই কোডটি রয়েছে এবং আপনার একটি লোডার ইন্টারফেস এবং একটি ওয়েবলডার রয়েছে যা এই ইন্টারফেসটি প্রয়োগ করে।

package main

import "fmt"

// Loader defines a content loader
type Loader interface {
    Load(src string) string
}

// WebLoader is a web content loader
type WebLoader struct{}

// Load loads the content of a page
func (w *WebLoader) Load(src string) string {
    return fmt.Sprintf("I loaded this page %s", src)
}

func main() {
    webLoader := WebLoader{}
    loadContent(webLoader)
}

func loadContent(loader Loader) {
    loader.Load("google.com")
}

সুতরাং এই কোডটি আপনাকে এই সংকলনের সময় ত্রুটি দেবে

সুতরাং আপনাকে কেবল যা করতে হবে তা হল webLoader := WebLoader{}নিম্নলিখিতগুলিতে পরিবর্তন করা:

webLoader := &WebLoader{} 

সুতরাং কেন এটি সংশোধন হবে কারণ আপনি func (w *WebLoader) Loadপয়েন্টার রিসিভার গ্রহণ করার জন্য এই ফাংশনটিকে সংজ্ঞায়িত করেন । আরও ব্যাখ্যার জন্য দয়া করে @ আইকজা এবং @ ক্যাকোরা উত্তরগুলি পড়ুন


6
এখনও পর্যন্ত এটি বোঝার সবচেয়ে সহজ মন্তব্য ছিল। এবং আমি যে সমস্যার মুখোমুখি ছিলাম তা সরাসরি সমাধান করে দিয়েছি ..
ম্যাক্সস 728

@ ম্যাক্সস 728 অনেকগুলি গো সমস্যাগুলির জবাব হিসাবে একমত, সম্মত।
মিলোস্মন্স

6

আর একটি ক্ষেত্রে যখন আমি এই জাতীয় জিনিসটি ঘটতে দেখেছি তা হ'ল আমি যদি এমন একটি ইন্টারফেস তৈরি করতে চাই যেখানে কিছু পদ্ধতি অভ্যন্তরীণ মানকে পরিবর্তন করতে পারে এবং অন্যরা তা করে না।

type GetterSetter interface {
   GetVal() int
   SetVal(x int) int
}

এই ইন্টারফেসটি প্রয়োগ করে এমন কিছু কিছু হতে পারে:

type MyTypeA struct {
   a int
}

func (m MyTypeA) GetVal() int {
   return a
}

func (m *MyTypeA) SetVal(newVal int) int {
    int oldVal = m.a
    m.a = newVal
    return oldVal
}

সুতরাং বাস্তবায়নকারী ধরণের সম্ভবত কিছু পদ্ধতি থাকবে যা পয়েন্টার রিসিভার এবং কিছু না যা আছে এবং যেহেতু আমার কাছে বিভিন্ন ধরণের বিভিন্ন জিনিস রয়েছে যা গেটরসেটর আমি আমার পরীক্ষাগুলিতে যাচাই করতে চাই যে তারা সমস্ত প্রত্যাশিত কাজ করছে।

যদি আমি এই জাতীয় কিছু করি:

myTypeInstance := MyType{ 7 }
... maybe some code doing other stuff ...
var f interface{} = myTypeInstance
_, ok := f.(GetterSetter)
if !ok {
    t.Fail()
}

তারপরে আমি পূর্বোক্ত "এক্স ওয়াই প্রয়োগ করে না (জেড পদ্ধতিটি পয়েন্টার রিসিভারযুক্ত)" ত্রুটিটি পাবে না (যেহেতু এটি একটি সংকলন-সময় ত্রুটি) তবে আমার পরীক্ষা কেন ব্যর্থ হচ্ছে ঠিক তাড়া করার জন্য আমার একটি খারাপ দিন হবে .. ।

পরিবর্তে আমাকে নিশ্চিত করতে হবে যে আমি পয়েন্টার ব্যবহার করে টাইপ চেক করি, যেমন:

var f interface{} = new(&MyTypeA)
 ...

বা:

myTypeInstance := MyType{ 7 }
var f interface{} = &myTypeInstance
...

তাহলে পরীক্ষায় খুশি সবাই!

কিন্তু অপেক্ষা করো! আমার কোডে সম্ভবত আমার কাছে এমন পদ্ধতি রয়েছে যা কোথাও একটি গিটারসেটর গ্রহণ করে:

func SomeStuff(g GetterSetter, x int) int {
    if x > 10 {
        return g.GetVal() + 1
    }
    return g.GetVal()
}

যদি আমি এই পদ্ধতিগুলি অন্য কোনও পদ্ধতির অভ্যন্তর থেকে কল করি তবে এটি ত্রুটি উত্পন্ন করবে:

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

নিম্নলিখিত কলগুলির মধ্যে যে কোনও একটি কাজ করবে:

func (m *MyTypeA) OtherThing(x int) {
    SomeStuff(m, x)
}

func (m MyTypeA) OtherThing(x int) {
    SomeStuff(&m, x)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.