类型如何成为Go中的函数?

类型如何成为Go中的函数?,go,syntax,Go,Syntax,我正在看 我看到: // 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 }

我正在看

我看到:

// 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
。它接受类型为
字符串的
,并返回三个值,以此类推

(我没有看到BNF的这种特殊结构,但我以前见过好几次这种结构,所以我相信它。)

在源代码的更高层,我注意到:

// keyLookupFunc adapts a raw function to be a KeyLookup.
type keyLookupFunc func() []testFifoObject
好的,实际上,
keyLookupFunc
是一种类型,它用来描述一个函数,它接受零参数并返回一个
testFifoObject
s片段

因此,如果我手里有一个
keyLookupFunc
类型的变量,我应该能够调用
GetByKey
“on”它。我不完全确定函数在这种情况下如何表现得像一个类型,但我相信它

现在,当我看到这些都是如何使用的,我:

注意
f.GetByKey(“foo”)
调用
f
是指向一个
DeltaFIFO
的指针


既然
f
是指向
DeltaFIFO
的指针,它怎么也可以是
keyLookupFunc
,这样该代码就可以调用
GetByKey
“on”它?如何连接这些点?

请注意,两个
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)
):

在这里也调用了三次(在
delta\u fifo\u test.go
文件中的
f.GetByKey(“foo”)
):


另一种方法是:

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

这是不使用(不调用)的

函数是Go中的一级公民:它可以有一个方法,甚至可以实现接口


DeltaFIFO
也不是
keyLookupFunc
,但它还有一个名为
GetByKey
的方法。两种不同的类型可以有一个同名的方法,没有问题;我应该看到这一点;真尴尬。这就意味着,这个
GetByKey
函数并没有在剩下的部分中使用,对吗?看起来好像没有,可能是遗留的,可能是以后使用的,我不知道。如果您这样做了,您可以看到该标识符仅在一些已有1年历史的文档中使用。。。如果您这样做,您将看到没有与
keyLookupFunc
类型匹配的实际函数。。。顺便说一句,如果您对函数类型和方法感兴趣,请查看
net/http.HandlerFunc
,它很有名。FWIW,函数的“行为方式与类型不同”。它的行为就像一个值(它是这样的),它有一个类型(每个值都有)。在我看来,答案的第二部分似乎不正确,返回的是
*DeltaFIFO
的实例,而不是
keyLookupFunc
的实例。在我看来,
keyLookupFunc
及其方法
GetByKey
似乎没有在任何地方使用。当然,除非我错过了什么;谢谢你的回答。我倾向于同意@mkopriva;你提到的三个调用正是我要问的。我不明白这里的
GetByKey
函数调用的“目标”怎么可能是
keyLookupFunc
,这似乎是一个要求。a.R的答案是正确的。您遇到的问题是,您在
keyLookupFunc
类型上找到了一个名为
GetByKey
的方法,但是许多
GetByKey
方法可以与各种接收器一起使用。事实上,
DeltaFIFO
有自己的
GetByKey
(A.R在开始时引用了它),所以最初发布的代码中没有任何东西是非常调用
GetByKey
keyLookupFunc
接收器;是的,好的,我完全颠倒了他/她的答案!现在我重读了一遍,我看到他/她在说,
keyLookupFunc
接收器上可调用的
GetByKey
函数从未使用过@A.R.我会给你答案的。谢谢大家的帮助。谢谢,@A.R;一辈子前,我对Perl进行了大量编程,Go接收器让我想起了Perl中OO方法的工作方式,其中“target”实际上只是函数的另一个语法辅助参数。谢谢你的例子。
// 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)
}
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
}