2016-11-21 5 views
-2

dieser Code Gegeben zu finden ...Schnittstelle Methode kann nicht auf Unterklasse von Superklasse

type BaseItf1 interface { 
    getName() string 
    clone() *BaseStruct 
} 

type BaseStruct struct { 
    BaseItf1 
} 

func (bs *BaseStruct) cloneAndGetName() string { 
    sc := bs.clone() 
    return sc.getName() 
} 

type SubClass struct { 
    BaseStruct 
} 

func (sc *SubClass) getName() string { 
    return "A" 
} 

func (sc *SubClass) clone() *SubClass { 
    return &SubClass{} 
} 

func main() { 
    sc := &SubClass{} 
    fmt.Printf("-> %s\n", sc.clone().getName()) 
    fmt.Printf("-> %s\n", sc.cloneAndGetName()) 
} 

Ich kann nicht ganz verstehen, warum ich immer diese Fehlermeldung:

panic: runtime error: invalid memory address or nil pointer dereference 
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x2004a] 

Der Anruf zu clone in main funktioniert natürlich perfekt.

In cloneAndGetName kann die Methode clone jedoch nicht aufgerufen werden. bs wird in einen Zeiger auf BaseStruct eingegeben, der die BaseItf Schnittstelle mit der clone Methode hat. Es scheint, als ob die konkrete sc Instanz in main, die aufgerufen cloneAndGetName weiß, wie die clone Methode zu finden.

Was fehlt mir? Gibt es einen besseren Weg? In meinem echten Code benötige ich eine Möglichkeit, eine neue Instanz eines Objekts aus einem gemeinsam genutzten Code zu erstellen.

+0

Der erste Aufruf von 'sc.clone()' gibt den Fehler Sie sehen, und nicht der Anruf in 'cloneAndGetName'. Sie können main mit 'sc: = & SubClass {}; sc.clone() 'zu verifizieren. –

+0

Ich bin mir nicht sicher, Paul. Wenn ich 'fmt.Printf (" ->% s \ n ", sc.clone(). GetName())' kommentiere, wird der Fehler fortgesetzt. – object88

+0

Beide sind fehlerhaft, aber der eine, der zuerst erscheint (der 'sc.clone()' in main), verursacht den Fehler, den Sie sehen. Wenn Sie es auskommentieren, erhalten Sie den gleichen Fehler von dem anderen Befehl. Der Text Ihrer Frage deutet darauf hin, dass Sie der Meinung waren, dass nur der zweite (der Code in "cloneAndGetName") den Fehler verursacht und dass "der Aufruf von' clone' in 'main' natürlich perfekt funktioniert." –

Antwort

2

bs.clone() schlägt fehl, weil es bs.BaseItf1.clone() und bs.BaseItf1 zu nennen versucht nil ist. Sie können das für *SubClass definierte clone() nicht von einer Variablen vom Typ *BaseStruct aufrufen. Das Einbetten von Typen in Go ist nicht das Gleiche wie das Unterklassifizieren in anderen Sprachen.

+0

In der Tat. Ich habe zahlreiche Beispiele genau dieses Problems gelesen, aber ich habe es immer noch nicht in meinem eigenen Code gesehen. Vielen Dank! – object88

0

sollten Sie zuerst die Funktion in der Schnittstelle implementieren.

package main 

import (
    "fmt" 
) 

type BaseItf1 interface { 
    getName() string 
    clone() *BaseStruct 
} 

type BaseStruct struct { 
    BaseItf1 
} 

func (bs *BaseStruct) cloneAndGetName() string { 
    sc := bs.clone() 
    return sc.getName() 
} 

func (bs *BaseStruct) getName() string { 
    return "" 
} 

func (bs *BaseStruct) clone() *BaseStruct { 
    return nil 
} 

type SubClass struct { 
    BaseStruct 
} 

func (sc *SubClass) getName() string { 
    return "A" 
} 

func (sc *SubClass) clone() *SubClass { 
    return &SubClass{} 
} 

func main() { 
    sc := &SubClass{} 
    fmt.Printf("-> %s\n", sc.clone().getName()) 
    fmt.Printf("-> %s\n", sc.cloneAndGetName()) 
} 
+0

Ich entschuldige mich; Ich hatte einige falsche Methodendeklarationen, die oben behoben wurden. Die Implementierung der Methoden in 'BaseStruct' ruft jedoch nicht die Überschreibungen in' SubClass' auf, daher ist das Ergebnis nicht wie erwartet. – object88

+0

sollten Sie Geräte für BaseStruct zuerst – duguying

+0

hinzufügen und dann wird '-> A' – duguying

0

Wenn Sie eine Struktur haben, und Sie wollen eine Schnittstelle Sie alle Methoden dieser Schnittstelle zu implementieren, müssen gerecht zu werden, es ist anders, wenn Sie eine Schnittstelle mit anderen Schnittstelle innen haben, für structs es ist nur ein Feld hat, Wenn Sie den Code einchecken sc.BaseItf1 hat einen Typ und Wert, so der Aufruf an .clone() und .cloneAndGetName() sind fehlgeschlagen. Implementiert die Methoden hier:

type BaseItf1 interface { 
    getName() string 
    clone() *BaseStruct 
} 

type BaseStruct struct { 
    BaseItf1 // shortcut to BaseItf1 BaseItf1 <fieldName> <Type> 
} 

func (bs *BaseStruct) clone() *BaseStruct { 
    return &BaseStruct{} 
} 

func (bs *BaseStruct) getName() string { 
    // 
    // maybe BaseStruct should have a field Name, not sure if you want to 
    // in that case we can do: 
    // 
    // return bs.Name 

    return "a BaseStruct has no name" 
} 

func (bs *BaseStruct) cloneAndGetName() string { 
    sc := bs.clone() 
    return sc.getName() 
} 

type SubClass struct { 
    BaseStruct 
} 

func (sc *SubClass) methodA() string { 
    return "A" 
} 

func (sc *SubClass) methodB() *SubClass { 
    return &SubClass{} 
} 

func main() { 
    sc := &SubClass{} 

    fmt.Printf("type: %T and value: %v \n\n", sc.BaseItf1, sc.BaseItf1) 

    fmt.Printf("-> %q\n", sc.clone().getName()) 
    fmt.Printf("-> %q\n", sc.cloneAndGetName()) 
} 

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

+0

Ich hatte anfangs einige falsche Methodendeklarationen; habe sie oben korrigiert. Wenn Sie jedoch Ihrem Beispiel folgen, wird der erwartete/gewünschte Fehler nicht angezeigt. Die Methodenüberschreibungen in 'SubClass' werden nicht aufgerufen, nur die Methoden in' BaseStruct'. – object88

1

Sie verwechseln Einbettung mit Interface Fulfillment. In seinem aktuellen Zustand haben Sie eine Struktur SubClass, die die Struktur BaseStruct einbettet, die dann eine Schnittstelle einbettet BaseItf1. Sie haben jedoch ein Problem: SubClass überschreibt nicht die cloneAndGetName() Methode. Als solche wird diese Methode auf der eingebetteten Struktur BaseStruct aufgerufen. Eingebettete Methodenaufrufe werden unter Verwendung der eingebetteten Struktur als Empfänger und nicht der eingebetteten Struktur aufgerufen. Die BaseStruct Struktur hat somit nur Zugriff auf ihre eigenen Methoden, nicht die der SubClass Struktur, die sie einhüllt. Da diese Methoden selbst das Ergebnis der eingebetteten Schnittstelle BaseItf1 sind, ruft BaseStruct diese Methoden auf dieser eingebetteten Schnittstelle auf, nämlich nil. Dies löst natürlich einen segfault aus.

In diesem Fall scheint es so zu sein, dass Sie eine Standardmethode für eine Basisstruktur definieren möchten, diese dann jedoch mit einer Unterklasse überschreiben können.In diesem Fall wird eine Instanz von SubClass in das Interface Feld innerhalb der BaseClass platzieren: In diesem Fall

sc := BaseStruct{&SubClass{}} 
fmt.Printf("-> %s\n", sc.clone().getName()) 
fmt.Printf("-> %s\n", sc.cloneAndGetName()) 

, sc.closeAndGetName() wird auf den BaseStruct genannt werden, aber die clone() und getName() fordert die substruct auftreten.

Sie können sogar Standardverhalten definieren, wenn die Schnittstelle null ist:

type BaseItf1 interface { 
    getName() string 
    clone() *BaseStruct 
} 

type BaseStruct struct { 
    sub BaseItf1 
} 

func (bs *BaseStruct) cloneAndGetName() string { 
    sc := bs.clone() 
    return sc.getName() 
} 

func (bs *BaseStruct) getName() string { 
    if bs.sub != nil { 
    return bs.sub.getName() 
    } 
    // default behavior 
    return "<nil>" 
} 

func (bs *BaseStruct) clone() *BaseStruct { 
    if bs.sub != nil { 
    return bs.sub.clone() 
    } 
    // default behavior 
    return bs 
} 

type SubClass struct { 
    // Doesn't need to embed BaseStruct 
    // ... 
} 

func (sc *SubClass) getName() string { 
    return "A" 
} 

func (sc *SubClass) clone() *BaseStruct { 
    return &BaseStruct{&SubClass{}} 
} 

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

Verwandte Themen