2014-08-31 4 views
8

Ich versuche, eine Allzweck-Wrapper für Abonnements zu schreiben, so etwas wie:Golang: Kann ich zu gieße chan Schnittstelle {}

type Subscriber interface{ 
    Subscribe(addr string) chan interface{} 
} 

Angenommen, es gibt eine Bibliothek, die ich verwenden möchte, die eine Methode subscribe hat in es, aber die eine chan library.Object verwendet. Ich möchte in der Lage sein, etwas zu tun wie:

Derzeit glaube ich nicht, dass eine solche Besetzung möglich ist. Und ich möchte die zugrunde liegende Bibliothek nicht ändern, da der Wrapper von Bibliotheksimplementierungen unabhängig sein sollte.

Ich habe Is there a way to cast Structs for sending over a channel gesehen, aber in diesem Fall kann die Anwendung geändert werden, um den Bedarf zu erfüllen. Hier kann es nicht. Ist das möglich? Gibt es einen besseren Weg? Eine Lösung besteht darin, in einem Allzweckkanal in Subscribe zu gehen und unablässig auf chan library.Object zu warten und alles abzufeuern, das auf meinem allgemeinen Kanal ankommt, aber ich habe nicht besonders gerne einen anderen Kanal einführen müssen, nur um herumzukommen der Typ gegossen.

+2

Go kein Konzept von "cast" hat. Machen Sie Konvertierungen, geben Sie Assertions und Interfaces ein (und geben Sie Switches ein) und das war's. Typkonvertierungen kommen am nächsten in z. C. Talking über Casts und Cast funktioniert nicht, wird nur Ihre Sicht auf das Problem verwischen, die durch die Verwendung von Typ-Konvertierungen (funktioniert nicht in Ihrer Situation!), Geschickte Verwendung von Schnittstellen und geeignete Typ Assertions/Switches möglicherweise mit kombiniert werden kann Betrachtung. Die meisten "General Purpose" Zeug in Go ist zum Scheitern verurteilt oder wird langsam durch Knietiefe waten in Reflexion. – Volker

Antwort

4

Nein, Sie können dies nicht mit nur einer Besetzung tun. Sie müssen einen zusätzlichen Kanal verwenden, wie Sie bereits in Erwägung gezogen haben. Zum Glück gibt es dafür bereits eine Hilfs-Bibliothek (Disclaimer: Ich habe sie geschrieben). Sie möchten die Wrap Funktion.

+1

Zahlen. Schande. vielleicht werden die Autoren in Zukunft die Typumschaltung erweitern, um dies zu unterstützen. Bei Arrays und Maps haben wir das gleiche Problem, aber zumindest dort können Sie die Elemente durchlaufen und den Schalter {} nacheinander eingeben. Es sollte einen Weg geben, es mit einem Kanal zu tun, aber vielleicht gibt es einen guten Grund nicht? – Ethan

+0

Der Grund ist nicht, dass die Typen grundlegend unterschiedliche Speicherlayouts haben, also ist es nicht so einfach wie ein "cast" in C wäre. Zum Beispiel sieht ein [] struct {x, y int} ganz anders aus als ein [] Schnittstelle {}, so dass Sie nicht einfach "vorgeben" können, Sie müssen die manuelle Konvertierung durchführen. Im Gegensatz zu einfachen Umwandlungen kann die Umwandlung teuer sein (wie Sie sagen, Sie müssen jedes Element durchlaufen), also entschieden sie sich, es nicht zu verstecken, weil es nicht dasselbe ist. – Evan

1

Für alle anderen, dass in dieser Frage stolpert und will einige Inline-Code:

// wrap a timeout channel in a generic interface channel 
func makeDefaultTimeoutChan() <-chan interface{} { 
    channel := make(chan interface{}) 
    go func() { 
    <-time.After(30 * time.Second) 
    channel <- struct{}{} 
    }() 
    return channel 
} 

// usage 
func main() { 
    resultChannel := doOtherThingReturningAsync() 
    cancel := makeDefaultTimeoutChan() 
    select { 
    case <-cancel: 
     fmt.Println("cancelled!") 
    case results := <-resultChannel: 
     fmt.Printf("got result: %#v\n", results) 
    } 
} 
Verwandte Themen