在controller-runtime中,有大量的这种**短横线**写法:
```
// Implement reconcile.Reconciler so the controller can reconcile objects
var _ reconcile.Reconciler = &reconcileReplicaSet{}
```
后面这个reconcile.Reconciler是变量的类型吗?看下源码
```
type Reconciler interface {
// Reconciler performs a full reconciliation for the object referred to by the Request.
// The Controller will requeue the Request to be processed again if an error is non-nil or
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
Reconcile(Request) (Result, error)
}
```
这个短横线是什么意思呢?是变量名吗?然后不用这个变量,只用的它的init方法?
有点不理解。
首先 go里要求所有的变量在定义后都需要被使用(包级变量除外)。
所以经常需要用 _ 来存放不使用的变量。
其次,合理加这个代码是为了保证 &reconcileReplicaSet{} 实现了 reconcile.Reconciler 接口。
我不喜欢把这种的代码放在主逻辑里,一般放在测试代码里验证。
#2
更多评论
没有人回答,我在这这里贴下我在微信群里询问到的答案:
1. 首先贴上[github地址](https://github.com/kubernetes-sigs/controller-runtime/blob/a4b50a42e0bc88020e90ba5d948a8941e9cf9aff/examples/builtins/controller.go)
2. 完整代码如下:
```go
// reconcileReplicaSet reconciles ReplicaSets
type reconcileReplicaSet struct {
// client can be used to retrieve objects from the APIServer.
client client.Client
log logr.Logger
}
// Implement reconcile.Reconciler so the controller can reconcile objects
var _ reconcile.Reconciler = &reconcileReplicaSet{}
func (r *reconcileReplicaSet) Reconcile(request reconcile.Request) (reconcile.Result, error) {
// set up a convenient log object so we don't have to type request over and over again
log := r.log.WithValues("request", request)
// Fetch the ReplicaSet from the cache
rs := &appsv1.ReplicaSet{}
err := r.client.Get(context.TODO(), request.NamespacedName, rs)
if errors.IsNotFound(err) {
log.Error(nil, "Could not find ReplicaSet")
return reconcile.Result{}, nil
}
if err != nil {
return reconcile.Result{}, fmt.Errorf("could not fetch ReplicaSet: %+v", err)
}
// Print the ReplicaSet
log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
// Set the label if it is missing
if rs.Labels == nil {
rs.Labels = map[string]string{}
}
if rs.Labels["hello"] == "world" {
return reconcile.Result{}, nil
}
// Update the ReplicaSet
rs.Labels["hello"] = "world"
err = r.client.Update(context.TODO(), rs)
if err != nil {
return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
}
return reconcile.Result{}, nil
}
```
3. 这里其实是类型断言
**要求reconcileReplicaSet结构体实现reconcile.Reconciler这个接口,否则编译时就会报错**
# 代码分析
1. 看上面的代码,首先是定义了一个结构体reconcileReplicaSet
2. 紧接着,就断言这个接构体实现了reconcile.Reconciler接口
3. 然后是这个结构体的真正实现接口的方法。
***从这个顺序上可以看到,代码只在第一步定义了结构体,但是在第三步才实现接口,但是类型判断是在第二步,如果按顺序肯定会报错,那既然是这样写,肯定是没有错的。原因在哪呢?***
#1
<a href="/user/jarlyyn" title="@jarlyyn">@jarlyyn</a> 这个我已经分析出来了,麻烦看下第一评论中的问题。《代码分析》
#3