2017-11-11 2 views
4

Ich bin ein Go-Rookie.Wie wird ein Typ in Go zu einer Funktion?

Ich sehe some Kubernetes source code.

Ich sehe dies:

// GetByKey returns the key if it exists in the list returned by kl. 
func (kl keyLookupFunc) GetByKey(key string) (interface{}, bool, error) { 
    for _, v := range kl() { 
     if v.name == key { 
      return v, true, nil 
     } 
    } 
    return nil, false, nil 
} 

Ich weiß, dunstig, wie dies zu lesen, aber ich bin sicher, ich werde meine Terminologie falsch machen: Es gibt eine Art irgendwo keyLookupFunc genannt, und kl ist effektiv ein Instanz davon, und diese Funktion mit dem Namen GetByKey kann darauf aufgerufen werden. Er akzeptiert ein key, dessen Typ string ist, und es gibt drei Werte, etc. etc.

(I für diese spezielle Konstruktion finden Sie in die BNF nicht zu my best guess as to where it should live in the language specification, aber ich habe diese Konstruktion mehrmals vor, so gesehen, die ich nehmen sie es auf den Glauben)

Higher im Quellcode, ich dies bemerken.

// keyLookupFunc adapts a raw function to be a KeyLookup. 
type keyLookupFunc func() []testFifoObject 

OK, also in der Tat keyLookupFunc ist eine Art, und es wird verwendet, um etwas zu beschreiben, die eine Funktion ist, die nimmt Zero-Parameter und gibt ein Stück testFifoObject s zurück.

So naiv, wenn ich eine keyLookupFunc -type Variable in meiner Hand habe, sollte ich in der Lage sein, GetByKey "on" it anzurufen. Ich bin mir nicht ganz sicher, wie sich eine Funktion in dieser Situation wie ein Typ verhalten kann, aber ich nehme es im Glauben.

Wenn ich jetzt schauen, um zu sehen, wie das alles verwendet wird, ich see this partial stuff:

func TestDeltaFIFO_requeueOnPop(t *testing.T) { 
    f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil) 

    f.Add(mkFifoObj("foo", 10)) 
    _, err := f.Pop(func(obj interface{}) error { 
     if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { 
      t.Fatalf("unexpected object: %#v", obj) 
     } 
     return ErrRequeue{Err: nil} 
    }) 
    if err != nil { 
     t.Fatalf("unexpected error: %v", err) 
    } 
    if _, ok, err := f.GetByKey("foo"); !ok || err != nil { 
     t.Fatalf("object should have been requeued: %t %v", ok, err) 
    } 

Notiere die f.GetByKey("foo") Aufruf. f ist ein Zeiger auf eine , die I just happen to know is returned by NewDeltaFIFO.

Da f ein Zeiger auf eine DeltaFIFO ist, wie kann es auch ein keyLookupFunc so beschaffen sein, dass dieser Code GetByKey „auf“ es nennen kann? Wie verbinde ich diese Punkte?

+3

'DeltaFIFO' ** ist auch nicht **' keyLookupFunc', aber ** es hat auch eine Methode ** genannt 'GetByKey' https://github.com/kubernetes/kubernetes/blob/ master/staging/src/k8s.io/client-gehen/tools/cache/delta_fifo.go # L392-L402. Zwei verschiedene Typen können eine Methode mit dem gleichen Namen haben, kein Problem. – mkopriva

+0

Vielen Dank; Ich hätte das sehen sollen; wie peinlich. Das heißt aber, dass diese 'GetByKey'-Funktion im Rest dieser [.go'-Datei] nicht verwendet wird (https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io /client-go/tools/cache/delta_fifo.go), oder? –

+1

Es scheint nicht, vielleicht ist es Erbe, vielleicht ist es etwas für den späteren Gebrauch bestimmt, ich weiß es nicht. Wenn Sie [diese Suche] (https://github.com/kubernetes/kubernetes/search?utf8=%E2%9C%93&q=keyLookupFunc&type=) ausführen, können Sie sehen, dass diese Kennung nur in einer einjährigen Dokumentation verwendet wird. .. Und wenn du [diese Suche] (https://github.com/kubernetes/kubernetes/search?utf8=%E2%9C%93&q=testFifoObject&type=) machst, wirst du sehen, dass es keine tatsächliche Funktion gibt, die mit der übereinstimmt 'keyLookupFunc' Typ ... Übrigens, wenn Sie an Funktionstypen mit Methoden interessiert sind, schauen Sie in' net/http.HandlerFunc', es ist berühmt. – mkopriva

Antwort

4

Hinweis die beide GetByKey Methoden sind zwei getrennte Verfahren auf zwei verschiedene Arten, (zwei verschiedene Arten mit einem Verfahren mit dem gleichen Namen):

Hinweis der letzten f.GetByKey ist:

// GetByKey returns the complete list of deltas for the requested item, 
// setting exists=false if that list is empty. 
// You should treat the items returned inside the deltas as immutable. 
func (f *DeltaFIFO) GetByKey(key string) (item interface{}, exists bool, err error) { 
    f.lock.RLock() 
    defer f.lock.RUnlock() 
    d, exists := f.items[key] 
    if exists { 
     // Copy item's slice so operations on this slice (delta 
     // compression) won't interfere with the object we return. 
     d = copyDeltas(d) 
    } 
    return d, exists, nil 
} 

und diese einmal hier (in delta_fifo.go Datei auf return f.GetByKey(key)) genannt:

// Get returns the complete list of deltas for the requested item, 
// or sets exists=false. 
// You should treat the items returned inside the deltas as immutable. 
func (f *DeltaFIFO) Get(obj interface{}) (item interface{}, exists bool, err error) { 
    key, err := f.KeyOf(obj) 
    if err != nil { 
     return nil, false, KeyError{obj, err} 
    } 
    return f.GetByKey(key) 
} 

Und auch genannt drei hier mal (in delta_fifo_test.go Datei auf f.GetByKey("foo")):

func TestDeltaFIFO_requeueOnPop(t *testing.T) { 
    f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil) 

    f.Add(mkFifoObj("foo", 10)) 
    _, err := f.Pop(func(obj interface{}) error { 
     if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { 
      t.Fatalf("unexpected object: %#v", obj) 
     } 
     return ErrRequeue{Err: nil} 
    }) 
    if err != nil { 
     t.Fatalf("unexpected error: %v", err) 
    } 
    if _, ok, err := f.GetByKey("foo"); !ok || err != nil { 
     t.Fatalf("object should have been requeued: %t %v", ok, err) 
    } 

    _, err = f.Pop(func(obj interface{}) error { 
     if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { 
      t.Fatalf("unexpected object: %#v", obj) 
     } 
     return ErrRequeue{Err: fmt.Errorf("test error")} 
    }) 
    if err == nil || err.Error() != "test error" { 
     t.Fatalf("unexpected error: %v", err) 
    } 
    if _, ok, err := f.GetByKey("foo"); !ok || err != nil { 
     t.Fatalf("object should have been requeued: %t %v", ok, err) 
    } 

    _, err = f.Pop(func(obj interface{}) error { 
     if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { 
      t.Fatalf("unexpected object: %#v", obj) 
     } 
     return nil 
    }) 
    if err != nil { 
     t.Fatalf("unexpected error: %v", err) 
    } 
    if _, ok, err := f.GetByKey("foo"); ok || err != nil { 
     t.Fatalf("object should have been removed: %t %v", ok, err) 
    } 
} 

Und die andere Methode ist:

// GetByKey returns the key if it exists in the list returned by kl. 
func (kl keyLookupFunc) GetByKey(key string) (interface{}, bool, error) { 
    for _, v := range kl() { 
     if v.name == key { 
      return v, true, nil 
     } 
    } 
    return nil, false, nil 
} 

und diese nicht benutzt wird (nicht genannt).

+1

Der zweite Teil Ihrer Antwort scheint mir falsch zu sein, [NewDeltaFIFO] (https://github.com/kubernetes/kubernetes/blob/2986b37de06fcd1bf94e68b49b6c8d87c389d3c2/staging/src/k8s.io/client-go/tools/cache/delta_fifo. go # L51) gibt eine Instanz von '* DeltaFIFO' und nicht von' keyLookupFunc' zurück. Mir scheint, dass 'keyLookupFunc' und seine Methode' GetByKey' nirgendwo benutzt werden. Es sei denn natürlich, ich vermisse etwas. – mkopriva

+0

Hallo; Danke für deine Antwort. Ich stimme eher mit @mkopriva überein; Die drei Aufrufe, auf die du dich beziehst, sind genau das, wonach ich frage. Ich sehe nicht, wie es möglich ist, dass das "Ziel" des "GetByKey" -Funktionsaufrufs hier möglicherweise ein 'keyLookupFunc' ist, was eine Anforderung zu sein scheint. –

+1

Die Antwort von A.R ist korrekt. Das Problem, das Sie haben, ist, dass Sie eine Methode mit dem Namen 'GetByKey' auf dem' keyLookupFunc' Typ gefunden haben, aber viele 'GetByKey' Methoden können mit verschiedenen Empfängern existieren. Tatsächlich hat "DeltaFIFO" seinen eigenen "GetByKey" (auf den A.R am Anfang verweist), so dass nichts in dem ursprünglich geposteten Code den "GetByKey" mit dem "keyLookupFunc" -Empfänger aufruft. – sberry

Verwandte Themen