Http 如果我显式地“引用”,为什么我的接口不包含值;关联的;

Http 如果我显式地“引用”,为什么我的接口不包含值;关联的;,http,go,Http,Go,嘿,伙计们,这段代码是模拟客户端、模拟服务器交互的一部分。我理解上下文有困难 在这里,我使用“WithValue”将我的跟踪器接口与上下文显式“关联”,然后使用WithContext将其注入到我的请求中。但当我检查请求的上下文是否包含跟踪器接口时,返回错误“此上下文应包含跟踪器”。我只是不理解的关于背景和价值的什么 var tracker Tracker ctx := context.WithValue(context.Background(), contextKey, tracker) r

嘿,伙计们,这段代码是模拟客户端、模拟服务器交互的一部分。我理解上下文有困难

在这里,我使用“WithValue”将我的跟踪器接口与上下文显式“关联”,然后使用WithContext将其注入到我的请求中。但当我检查请求的上下文是否包含跟踪器接口时,返回错误“此上下文应包含跟踪器”。我只是不理解的关于背景和价值的什么

var tracker Tracker

ctx := context.WithValue(context.Background(), contextKey, tracker)

req := httptest.NewRequest("GET", "localhost:12345/test", nil)
req.Header.Add(HEADER)

req = req.WithContext(ctx)

_, ok := ctx.Value(contextKey).(Tracker)
if !ok {
    log.Fatal("1: This context should contain a tracker")
}

Tracker
是一个接口,它没有设置为任何值,因此它是
nil
。因此,它不能将
nil
更改为
Tracker
,因此失败


问题不是
tracker
为零,而是它不包含实现
tracker
的具体类型的值。
tracker
的值可以是nil,这可以工作,但必须是“类型化”的nil

类型断言失败,因为类型断言和类型开关只有在被断言的实例具有具体类型时才起作用。通过声明、赋值、类型断言或类型开关大小写,值可以是具体类型

执行类型断言时
ctx.Value(contextKey)。(跟踪器)
这有(概念上)两个步骤:

  • 确定
    ctx.Value(contextKey)
    的具体类型
  • 确定该具体类型是否实现了跟踪程序
  • 这里有一个游乐场的例子,希望能更好地说明这一点:

    其中的
    DoAny()
    函数正在模拟当您将
    跟踪器放入上下文中,然后尝试使用类型断言检索它时发生的情况

    我知道这只是一个基本的例子,但使用
    var SomeInterfaceType
    不是很好的做法,即使您给它赋值。你应该使用具体的类型。或者更好,只要使用类型推断,就不必担心了。例如:

    type Foo interface {
        DoFoo() string
    }
    
    type MyFoo struct {}
    
    func (f *MyFoo) DoFoo() string {
        return "some foo value"
    }
    
    // not so good
    var f Foo = new(MyFoo)
    
    // good
    var f *MyFoo = new(MyFoo)
    
    // better
    f := new(MyFoo)
    
    这充分利用了接口在Go中是隐式的这一事实,并导致更明显和可维护的代码,特别是在大型项目中。声明具有接口类型的变量本质上是使变量具有极纯性,但接口的真正功能不是多态性。真正的力量在于将它们用作包的公开函数/方法的“功能需求”。有一条规则很好地说明了这一点,那就是

    编辑: 我编辑了我的原始答案,以纠正一些错误并做出一些改进。我还想回答OP的后续问题:

    我不明白的是,除非你有一个对象利用了跟踪器的方法,否则你的界面是零。这是正确的想法吗


    我认为你想说的是对的,但是用的词不太正确。首先,Go中没有对象,因为它不是面向对象的。在OOP语言中,对象保存类型的实例,Go使用变量和常量保存类型的实例。所以这个概念是存在的,但不是同名的。因此,您的
    tracker
    变量将是满足
    tracker
    接口的类型的实例,但其值为
    nil
    ,除非您将其指定为满足
    tracker
    接口的类型的非nil实例

    如果
    Tracker
    是一个接口,那么
    Tracker
    就是
    nil
    ,这意味着您没有添加值。啊,我明白了,所以跟踪器捕获的对象需要与ctx关联。value不应该是nil?它可以是nil,但您将返回nil(如果不退出,api总是返回nil),所以根本没有价值。您需要将一个值传递给“WithValue”。我遗漏了一点,那就是我确实有一个已定义的跟踪器接口。但我不明白的是,除非你有一个对象利用了追踪器的方法,否则你的界面是零。这是正确的想法吗?@user10178254很高兴这有帮助。我已经更新和修改了我的答案,希望能把事情弄清楚。