在我的包之外使用结构体的多态性。

huangapple go评论74阅读模式
英文:

Polymorphism with struct from outside my package

问题

我正在尝试构建一个方法,使用Kubernetes client-go库,根据给定的*metav1.OwnerReference获取并返回实际的资源。我有以下代码:

func fetchResource(ref *metav1.OwnerReference, options *RequestOptions) (*metav1.ObjectMeta, error) {
	switch ref.Kind {
	case "ReplicaSet":
		return options.Clientset.AppsV1().ReplicaSets(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
	case "Deployment":
		return options.Clientset.AppsV1().Deployments(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
	case "Job":
		fallthrough
    // 更多的代码...
	default:
		return nil, nil
	}
}

这段代码无法编译,因为:

> 无法将类型为*"k8s.io/api/apps/v1".ReplicaSet的值作为返回语句中的*"k8s.io/apimachinery/pkg/apis/meta/v1".ObjectMeta类型的值使用

我猜想,由于文档中基本上所有资源都嵌入了metav1.ObjectMeta,我可以将其作为返回类型使用。

我尝试创建并返回一个interface,但意识到我无法为我的包之外的类型实现它:

type K8sResource interface {
	Name() string
	Kind() string
	OwnerReferences() []metav1.OwnerReference
}

func (pod *corev1.Pod) Name() string {
	return pod.Name
}
func (pod *corev1.Pod) Kind() string {
	return pod.Kind
}
func (pod *corev1.Pod) OwnerReferences() []metav1.OwnerReference {
	return pod.OwnerReferences
}

这段代码无法编译,因为:

> 无效的接收器*"k8s.io/api/core/v1".Pod(在此包中未定义的类型)

在这里,什么是惯用且正确的解决方案?

英文:

I'm trying to build a method that, using the Kubernetes client-go library, fetches and returns the actual Resources for a given *metav1.OwnerReference. I have this:

func fetchResource(ref *metav1.OwnerReference, options *RequestOptions) (*metav1.ObjectMeta, error) {
	switch ref.Kind {
	case "ReplicaSet":
		return options.Clientset.AppsV1().ReplicaSets(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
	case "Deployment":
		return options.Clientset.AppsV1().Deployments(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
	case "Job":
		fallthrough
    // more stuff...
	default:
		return nil, nil
	}
}

This code does not compile because:

> cannot use options.Clientset.AppsV1().ReplicaSets(options.Namespace).Get(options.Context, ref.Name, (metav1.GetOptions literal)) (value of type *"k8s.io/api/apps/v1".ReplicaSet) as *"k8s.io/apimachinery/pkg/apis/meta/v1".ObjectMeta value in return statement

My guess was that since the documentation says that basically all resources embedd the metav1.ObjectMeta, I could use it as a return type.

I tried creating and returning an interface instead, but realized I can't implement it for types outside my package:

type K8sResource interface {
	Name() string
	Kind() string
	OwnerReferences() []metav1.OwnerReference
}

func (pod *corev1.Pod) Name() string {
	return pod.Name
}
func (pod *corev1.Pod) Kind() string {
	return pod.Kind
}
func (pod *corev1.Pod) OwnerReferences() []metav1.OwnerReference {
	return pod.OwnerReferences
}

This code does not compile because:

> invalid receiver *"k8s.io/api/core/v1".Pod (type not defined in this package)

What would be the idiomatic and correct solution here?

答案1

得分: 2

如果你想将导入的类型作为它们尚未实现的接口返回,你可以将它们包装在已实现该接口的类型中。

例如:

type K8sResource interface {
	Name() string
	Kind() string
	OwnerReferences() []metav1.OwnerReference
}
type replicaSet struct{ *v1.ReplicaSet }

func (s replicaSet) Name() string {
	return s.ReplicaSet.Name
}
func (s replicaSet) Kind() string {
	return s.ReplicaSet.Kind
}
func (s replicaSet) OwnerReferences() []metav1.OwnerReference {
	return s.ReplicaSet.OwnerReferences
}
func fetchResource(ref *metav1.OwnerReference, options *RequestOptions) (K8sResource, error) {
	switch ref.Kind {
	case "ReplicaSet":
		res, err := options.Clientset.AppsV1().ReplicaSets(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		return replicaSet{res}, nil // 包装起来
	case "Pod":
		res, err := options.Clientset.AppsV1().Pods(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		return pod{res}, nil // 包装起来
	case "Job":
		fallthrough
	// 更多的内容...
	default:
		return nil, nil
	}
}
英文:

If you want to return the imported types as an interface that they don't already implement, you can wrap them in types that do implement it.

For example:

type K8sResource interface {
	Name() string
	Kind() string
	OwnerReferences() []metav1.OwnerReference
}
type replicaSet struct{ *v1.ReplicaSet }

func (s replicaSet) Name() string {
	return s.ReplicaSet.Name
}
func (s replicaSet) Kind() string {
	return s.ReplicaSet.Kind
}
func (s replicaSet) OwnerReferences() []metav1.OwnerReference {
	return s.ReplicaSet.OwnerReferences
}
func fetchResource(ref *metav1.OwnerReference, options *RequestOptions) (K8sResource, error) {
	switch ref.Kind {
	case "ReplicaSet":
		res, err := options.Clientset.AppsV1().ReplicaSets(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		return replicaSet{res}, nil // wrap it up
	case "Pod":
		res, err := options.Clientset.AppsV1().Pods(options.Namespace).Get(options.Context, ref.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		return pod{res}, nil // wrap it up
	case "Job":
		fallthrough
	// more stuff...
	default:
		return nil, nil
	}
}

huangapple
  • 本文由 发表于 2021年8月27日 20:00:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/68953067.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定