pointers - X لا يتم تطبيق Y(... تحتوي الطريقة على مستقبل مؤشر)




go methods (2)

هناك العديد من الأسئلة والأجوبة على هذا السؤال " X لا يطبق Y (... تحتوي الطريقة على مستقبل مؤشر) " ، لكن يبدو لي أنهم يتحدثون عن أشياء مختلفة ، ولا ينطبقون على حالتي المحددة.

لذا ، بدلاً من جعل السؤال محددًا للغاية ، فأنا أجعله واسعًا وملخصًا - يبدو أن هناك العديد من الحالات المختلفة التي يمكن أن تحدث هذا الخطأ ، فهل يمكن لأحد أن يلخصها من فضلك؟

بمعنى ، كيفية تجنب المشكلة ، وإذا حدثت ، ما هي الاحتمالات؟ شكرا.


حالة أخرى عندما رأيت هذا النوع من الأشياء يحدث إذا كنت أرغب في إنشاء واجهة حيث تقوم بعض الطرق بتعديل قيمة داخلية والبعض الآخر لن يقوم بذلك.

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
}

لذلك من المحتمل أن يكون لنوع التطبيق بعض الأساليب التي هي مستقبلات المؤشر وبعضها غير موجود ولأنني لدي مجموعة متنوعة من هذه الأشياء المختلفة التي هي GetterSetters أود أن أتحقق من اختباراتي بأنهم جميعًا يقومون بما هو متوقع.

إذا كنت سأفعل شيئًا كهذا:

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

بعد ذلك ، لن أحصل على الخطأ السابق "X لا يطبق Y (الطريقة Z بها مستقبل المؤشر)" (لأنه خطأ وقت الترجمة) ، لكنني سأواجه يومًا سيئًا يطارد بالضبط سبب إخفاقي في الاختبار .. .

بدلاً من ذلك ، يجب أن أتأكد من قيامي بالتحقق من النوع باستخدام مؤشر ، مثل:

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

أو:

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

ثم كل شيء سعيد مع الاختبارات!

لكن انتظر! في الكود الخاص بي ، ربما يكون لدي طرق تقبل GetterSetter في مكان ما:

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

لإبقائه قصيرًا ، لنفترض أن لديك هذا الرمز وأن لديك واجهة Loader و WebLoader يقوم بتنفيذ هذه الواجهة.

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

لذلك سوف يمنحك هذا الرمز خطأ وقت الترجمة

./main.go:20:13: لا يمكن استخدام webLoader (اكتب WebLoader) كنوع Loader في الوسيطة to loadContent: لا يقوم WebLoader بتطبيق Loader (أسلوب التحميل يحتوي على مستقبل المؤشر)

ما عليك القيام به هو تغيير webLoader := WebLoader{} إلى ما يلي:

webLoader := &WebLoader{} 

فلماذا سوف إصلاح لأنك تحدد هذه الوظيفة func (w *WebLoader) Load لقبول المتلقي المؤشر. لمزيد من التوضيح ، يرجى قراءة إجاباتicza و @ Karora





interface