一个类型在Go中如何成为函数?

一个类型在Go中如何成为函数?

问题描述:

我是个新手。我正在寻找some Kubernetes source code一个类型在Go中如何成为函数?

我看到这一点:

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

我朦胧地知道如何阅读,但我敢肯定,我会得到我的术语错误:有一个地方叫keyLookupFunc类型,kl是有效的它的实例,并且可以调用名为GetByKey的此函数。它接受一个key类型为string,并返回三个值,等等,等等

(我没有看到BNF在my best guess as to where it should live in the language specification这个特殊的建筑,但我之前,所以见过这种结构好几次我只要相信)

越往上源代码

,我注意到这一点:

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

OK,所以确实keyLookupFunc是一种类型,它是用来描述的东西,是需要一个功能零参数并返回一片testFifoObject s。如此天真,如果我手上有一个keyLookupFunc-type变量,我应该可以调用GetByKey“on”。我不完全确定一个函数在这种情况下的行为如何,但我会信赖它。

现在,当我看看,看看这是怎么用的,我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) 
    } 

注意f.GetByKey("foo")调用。 f是指向DeltaFIFO,其中I just happen to know is returned by NewDeltaFIFO

鉴于f是一个指向DeltaFIFO,怎么还可以是这样keyLookupFunc,这个代码可以“”它叫GetByKey?我如何连接这些点?

+3

'DeltaFIFO' **是不是也**'keyLookupFunc',但**它也有一个方法叫**'GetByKey' https://github.com/kubernetes/kubernetes/blob/主/分期/ src目录/ k8s.io /客户去/工具/缓存/ delta_fifo.go#L392-L402。两种不同的类型可以有一个名称相同的方法,在那里没有问题。 – mkopriva

+0

谢谢;我应该看到的;多么尴尬。然而,这意味着这个'GetByKey'函数不会在[this'.go'文件]的其余部分使用(https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io /client-go/tools/cache/delta_fifo.go),对不对? –

+1

看起来好像不是,也许它是遗留的,也许它是为了以后使用的东西,我不知道。如果你[搜索](https://github.com/kubernetes/kubernetes/search?utf8=%E2%9C%93&q=keyLookupFunc&type=),你可以看到该标识符仅用于大约1年的文档。 ..如果你[搜索](https://github.com/kubernetes/kubernetes/search?utf8=%E2%9C%93&q=testFifoObject&type=),你会看到没有实际的功能匹配'keyLookupFunc'类型...顺便说一下,如果你对函数类型感兴趣,可以看看'net/http.HandlerFunc',它很有名。 – mkopriva

注意两个GetByKey方法是在两个不同类型的两个单独的方法中,(两种不同类型的与具有相同名称的方法):

注意最后f.GetByKey是:

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

和这调用一次在这里(在delta_fifo.go文件在return f.GetByKey(key)):

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

而且也叫三这里次(delta_fifo_test.go文件在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) 
    } 
} 

而另一种方法是:

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

,这是不使用(不叫)。

+1

您的答案的第二部分对我来说似乎不正确,[NewDeltaFIFO](https://github.com/kubernetes/kubernetes/blob/2986b37de06fcd1bf94e68b49b6c8d87c389d3c2/staging/src/k8s.io/client-go/tools/cache/delta_fifo。去#L51)返回'* DeltaFIFO'的实例,而不是'keyLookupFunc'。对我来说''keyLookupFunc'和它的方法'GetByKey'不会在任何地方使用。当然,除非我错过了一些东西。 – mkopriva

+0

嗨;感谢您的回答。我倾向于同意@mkopriva;你引用的三个调用正是我所问的。我不明白这里GetByKey函数调用的“目标”有可能是'keyLookupFunc',这似乎是一个需求。 –

+1

A.R的回答是正确的。您遇到的问题是您在'keyLookupFunc'类型上找到了一个名为'GetByKey'的方法,但很多'GetByKey'方法可以与各种接收器一起存在。事实上,'DeltaFIFO'有它自己的'GetByKey'(在开始时就是A.R引用),所以最初发布的代码中没有任何东西是用'keyLookupFunc'接收器调用'GetByKey'。 – sberry

功能是Go的头等公民:它可以有一个方法,甚至可以实现接口。

https://play.golang.org/p/d-N4OKLirQ