dongpo1846 2017-11-11 19:05
浏览 16
已采纳

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

I am a Go rookie.

I am looking at some Kubernetes source code.

I see this:

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

I know hazily how to read this, but I'm sure I'm going to get my terminology wrong: There's a type somewhere called keyLookupFunc, and kl is effectively an instance of it, and this function, named GetByKey can be called on it. It accepts a key whose type is string, and it returns three values, etc. etc.

(I don't see the BNF for this particular construction at my best guess as to where it should live in the language specification, but I've seen this construction several times before so I take it on faith.)

Higher up in the source code, I notice this:

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

OK, so indeed keyLookupFunc is a type, and it is used to describe something that is a function that takes zero parameters and returns a slice of testFifoObjects.

So naïvely, if I have a keyLookupFunc-typed variable in my hand, I should be able to call GetByKey "on" it. I am not entirely sure how a function can behave like a type in this situation, but I'll take it on faith.

Now when I look to see how this is all used, I 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)
    }

Note the f.GetByKey("foo") invocation. f is a pointer to a DeltaFIFO, which I just happen to know is returned by NewDeltaFIFO.

Given that f is a pointer to a DeltaFIFO, how can it also be a keyLookupFunc such that this code can call GetByKey "on" it? How do I connect these dots?

  • 写回答

2条回答 默认 最新

  • dougu7546 2017-11-11 19:50
    关注

    Note the twoGetByKey methods are two separate methods on two different types, (Two different types with a method with the same name):

    Note the last f.GetByKey is:

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

    and this called once here (in delta_fifo.go file at 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)
    }
    

    And also called three times here (in delta_fifo_test.go file at 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)
        }
    }
    

    And the other method is:

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

    and this is not used (not called).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?