Core The Basics

Object

Overview

Object 实例如下所示,基本都在 pkg/apis 目录下,自己查找即可。

Unstructured

Unstructured 与 Object 配合使用的场景如下

实例图如下

Scheme

Builder

Scheme

看一下 Scheme 的定义,前四项都是在维护 reflect.Type 与 schema.GroupVersionKind 的关系。defaulterFuncs 用于构建默认对象。

type Scheme struct {
    // versionMap allows one to figure out the go type of an object with
    // the given version and name.
    gvkToType map[schema.GroupVersionKind]reflect.Type

    // typeToGroupVersion allows one to find metadata for a given go object.
    // The reflect.Type we index by should *not* be a pointer.
    typeToGVK map[reflect.Type][]schema.GroupVersionKind

    // unversionedTypes are transformed without conversion in ConvertToVersion.
    unversionedTypes map[reflect.Type]schema.GroupVersionKind

    // unversionedKinds are the names of kinds that can be created in the context of any group
    // or version
    // TODO: resolve the status of unversioned types.
    unversionedKinds map[string]reflect.Type

    // Map from version and resource to the corresponding func to convert
    // resource field labels in that version to internal version.
    fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc

    // defaulterFuncs is an array of interfaces to be called with an object to provide defaulting
    // the provided object must be a pointer.
    defaulterFuncs map[reflect.Type]func(interface{})

    // converter stores all registered conversion functions. It also has
    // default converting behavior.
    converter *conversion.Converter

    // versionPriority is a map of groups to ordered lists of versions for those groups indicating the
    // default priorities of these versions as registered in the scheme
    versionPriority map[string][]string

    // observedVersions keeps track of the order we've seen versions during type registration
    observedVersions []schema.GroupVersion

    // schemeName is the name of this scheme.  If you don't specify a name, the stack of the NewScheme caller will be used.
    // This is useful for error reporting to indicate the origin of the scheme.
    schemeName string
}

FieldLabelConversionFunc 用于将 label、value 转换为内部 label、value。

type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)

AddKnownTypes

AddKnownTypes 只需要注意一个问题,即从传入的 GroupVersion 通过 reflect.Type 的 Name 方法返回值作为 Kind 生成 GroupVersionKind,请看简化后的示例 Reflect Name Sample,示例代码可在 Go Playground 下执行。

AddUnversionedTypes

AddUnversionedTypes 原理如下。可以将 Unversioned Type 理解为一个 Object 挂载在一个 Group 上,且 Version 永不更新。

nameFunc

nameFunc 原理如下,只要注意返回类型优先为 Internal Type 就可以了。

Others

Conversion

Landscape

typePair 用来表示源类型与目标类型的组合;typeNamePair 存储类型及类型名称;DefaultNameFunc 用做默认的类型到 Name 的转换方法。ConversionFunc 定义了对象转换方法。

Core Function Definitions

DefaultNameFunc 实现如下所示

var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }

ConversionFunc 声明如下所示

type ConversionFunc func(a, b interface{}, scope Scope) error

FieldMappingFunc 将 key 转换为源结构及目标结构中的 Field

type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)

ConversionFuncs

Converter

将下列方法做简要说明:

doConversion

Converter 在执行对象转换方法时,如 ConvertDefaultConvert 允许传入一个 Meta 对象,并执行 doConversion 方法,在这个方法中构建 scope 对象。

Scope

defaultConvert

defaultConvert 处理默认的类型变换,传入的 sv, dv 已经经由 EnforcePtr 确保为可寻址。这部分代码是对 Go 中 reflect 包近乎完美的应用。 首先,处理基本类型的转换,即可通过 AssignableToConvertibleTo 转换的类型。

switch st.Kind() {
    case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
    // 这些类型后续处理
    default:
    // This should handle all simple types.
    if st.AssignableTo(dt) {
        dv.Set(sv)
        return nil
    }
    if st.ConvertibleTo(dt) {
        dv.Set(sv.Convert(dt))
        return nil
    }
}

然后根据 dv.Kind() 分别进行处理。

dv.Kind() -> reflect.Struct

直接返回 convertKV 方法的结果,但是,需要注意,首先将 sv、dv 分别转化为 Key/Value 的形式。toKVValue 方法请自行研究。

return c.convertKV(toKVValue(sv), toKVValue(dv), scope)

dv.Kind() -> reflect.Slice

case reflect.Slice:
    if sv.IsNil() {
        // Don't make a zero-length slice.
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
    for i := 0; i < sv.Len(); i++ {
        scope.setIndices(i, i)
        if err := c.convert(sv.Index(i), dv.Index(i), scope); err != nil {
            return err
        }
    }

dv.Kind() -> reflect.Ptr

case reflect.Ptr:
    if sv.IsNil() {
        // Don't copy a nil ptr!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.New(dt.Elem()))
    switch st.Kind() {
        case reflect.Ptr, reflect.Interface:
        return c.convert(sv.Elem(), dv.Elem(), scope)
        default:
        return c.convert(sv, dv.Elem(), scope)
    }

dv.Kind() -> reflect.Interface

case reflect.Interface:
    if sv.IsNil() {
        // Don't copy a nil interface!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    tmpdv := reflect.New(sv.Elem().Type()).Elem()
    if err := c.convert(sv.Elem(), tmpdv, scope); err != nil {
        return err
    }
    dv.Set(reflect.ValueOf(tmpdv.Interface()))
    return nil

dv.Kind() -> reflect.Map

case reflect.Map:
    if sv.IsNil() {
        // Don't copy a nil ptr!
        dv.Set(reflect.Zero(dt))
        return nil
    }
    dv.Set(reflect.MakeMap(dt))
    for _, sk := range sv.MapKeys() {
        dk := reflect.New(dt.Key()).Elem()
        if err := c.convert(sk, dk, scope); err != nil {
            return err
        }
        dkv := reflect.New(dt.Elem()).Elem()
        scope.setKeys(sk.Interface(), dk.Interface())

        if err := c.convert(sv.MapIndex(sk), dkv, scope); err != nil {
            return err
        }
        dv.SetMapIndex(dk, dkv)
    }

最后更新于