类型如何成为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
}