伙计们,这段代码是模拟客户端,模拟服务器交互的一部分。我在理解上下文时遇到麻烦。
在这里,我使用“ WithValue”将跟踪器接口与上下文明确“关联”,然后使用WithContext将其插入到我的请求中。但是,当我检查请求的上下文是否包含跟踪器接口时,会返回错误“此上下文应包含跟踪器”。我只是不了解上下文和WithValue是什么?
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")
}
答案 0 :(得分:0)
Tracker
是一个接口,未设置任何内容,因此为nil
。因此,它无法将nil
更改为Tracker
,因此失败。
答案 1 :(得分:0)
问题不是tracker
为nil,而是问题在于它不包含实现Tracker
的具体类型的值。 tracker
的值可以为nil,这可以工作,但是必须为“类型化” nil。
类型声明失败,因为类型声明和类型开关仅在被声明的实例具有具体类型时才起作用。通过声明,赋值,类型断言或类型转换大小写,值可以是具体类型。
当您进行类型断言ctx.Value(contextKey).(Tracker)
时
(从概念上来说)有两个步骤:
ctx.Value(contextKey)
的具体类型。Tracker
。下面是一个操场示例,希望可以更好地说明这一点:https://play.golang.org/p/ojYzLObkisd
其中的DoAny()
函数正在模拟当您将tracker
放入上下文,然后尝试使用类型断言来检索它时发生的情况。
我知道这只是一个基本示例,但是即使您确实为其分配了一个值,使用var something 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中是隐式的这一事实,并导致了更明显和可维护的代码,尤其是在大型项目中。声明具有接口类型的变量实际上是使变量具有多态性,但是接口的真正作用并非多态性。真正的威力在于将它们用作包装的公开功能/方法的“功能要求”。可以很好地说明这一点的规则是"Accept interfaces, return structs"。
编辑: 我已经编辑了原始答案,以纠正一些错误并进行了一些改进。我还想回答OP的后续问题:
我不明白的是,除非您有一个使用该跟踪器方法的对象,否则您的界面为nil。这是正确的想法吗?
我认为您要说的是正确的,但是所用的单词不太正确。首先,Go中没有 objects ,因为它不是面向对象的。在OOP语言中,对象包含类型的实例,而Go使用变量和常量来保存类型的实例。因此,该概念存在,但名称不同。因此,您的tracker
变量将是满足您的Tracker
接口类型的实例,但其值应为nil
,除非您为它分配了一个满足以下条件的类型的非null实例: Tracker
界面。