欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go語(yǔ)言代碼生成器code?generator使用示例介紹

 更新時(shí)間:2022年05月13日 16:41:16   作者:油膩中年李大鵝  
這篇文章主要為大家介紹了go語(yǔ)言代碼生成器code?generator的使用簡(jiǎn)單介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

代碼生成器介紹

client-go為每種k8s內(nèi)置資源提供了對(duì)應(yīng)的clientsetinformer。那么我們要監(jiān)聽和操作自定義資源對(duì)象,應(yīng)該如何做呢?

方式一:使用client-go提供的dynamicClient來操作自定義資源對(duì)象,當(dāng)然由于dynamicClient是基于RESTClient實(shí)現(xiàn)的,所以我們可以使用RESTClient來達(dá)到同樣的目的。

方式二: 使用conde-generator來幫我們生成我們需要的代碼,這樣我們就可以像使用client-go為k8s內(nèi)置資源對(duì)象提供的方式監(jiān)聽和操作自定義資源了。

code-generator

code-generator 就是 Kubernetes 提供的一個(gè)用于代碼生成的項(xiàng)目,它提供了以下工具為 Kubernetes 中的資源生成代碼:

  • deepcopy-gen: 生成深度拷貝方法,為每個(gè) T 類型生成 func (t* T) DeepCopy() *T 方法,API 類型都需要實(shí)現(xiàn)深拷貝
  • client-gen: 為資源生成標(biāo)準(zhǔn)的 clientset
  • informer-gen: 生成 informer,提供事件機(jī)制來響應(yīng)資源的事件
  • lister-gen: 生成 Lister,為 get 和 list 請(qǐng)求提供只讀緩存層(通過 indexer 獲?。?/li>

Informer 和 Lister 是構(gòu)建控制器的基礎(chǔ),使用這4個(gè)代碼生成器可以創(chuàng)建全功能的、和 Kubernetes 上游控制器工作機(jī)制相同的 production-ready 的控制器。

code-generator 還包含一些其它的代碼生成器,例如 Conversion-gen 負(fù)責(zé)產(chǎn)生內(nèi)外部類型的轉(zhuǎn)換函數(shù)、Defaulter-gen 負(fù)責(zé)處理字段默認(rèn)值。

大部分的生成器支持--input-dirs參數(shù)來讀取一系列輸入包,處理其中的每個(gè)類型,然后生成代碼:

? 1、部分代碼生成到輸入包所在目錄,例如 deepcopy-gen 生成器,也可以使用參數(shù)--output-file-base "zz_generated.deepcopy" 來定義輸出文件名

? 2、其它代碼生成到 --output-package 指定的目錄,例如 client-gen、informer-gen、lister-gen 等生成器

示例

接來下我們使用code-generator進(jìn)行實(shí)戰(zhàn)演示:

首先我們將項(xiàng)目拉到本地:

$ git clone https://github.com/kubernetes/code-generator.git
$ git checkout 0.23.3

然后我們進(jìn)入到cmd目錄下,就會(huì)看到我們上面介紹的工具:

接著我們對(duì)client-gen,deepcopy-gen,infromer-gen,lister-gen進(jìn)行安裝,會(huì)安裝到GOPATH的bin目錄下:

# 進(jìn)行安裝
$ go install ./cmd/{client-gen,deepcopy-gen,informer-gen,lister-gen}
# 獲取GOPATH路徑
$ go env | grep GOPATH
GOPATH="/Users/Christian/go"
# 查看
ls /Users/Christian/go/bin
client-gen     deepcopy-gen   goimports      lister-gen
controller-gen defaulter-gen  informer-gen   type-scaffold

發(fā)現(xiàn)我們已經(jīng)成功的安裝了,這時(shí)候我們就可以直接使用這些工具了,比如我們可以使用--help命令來查看如何使用client-gen:

當(dāng)然通常情況下我們不會(huì)去單獨(dú)的使用某一個(gè)工具。

接下來我們來創(chuàng)建我們的項(xiàng)目,此處我們可以仿照sample controller項(xiàng)目進(jìn)行編寫:

$ mkdir operator-test && cd operator-test
$ go mod init operator-test
$ mkdir -p pkg/apis/example.com/v1
?  operator-test tree
.
├── go.mod
├── go.sum
└── pkg
    └── apis
        └── example.com
            └── v1
                ├── doc.go
                ├── register.go
                └── types.go
4 directories, 5 files

接下來我們對(duì)v1下面的三個(gè)go文件進(jìn)行填充(可以直接復(fù)制sample-controller,對(duì)其進(jìn)行做簡(jiǎn)單修改):

doc.go主要是用來聲明要使用deepconpy-gen以及groupName。

// pkg/crd.example.com/v1/doc.go
// +k8s:deepcopy-gen=package
// +groupName=example.com
package v1

types.go主要是定義crd資源對(duì)應(yīng)的go中的結(jié)構(gòu)。

// pkg/crd.example.com/v1/types.go
package v1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Bar is a specification for a Bar resource
type Bar struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`
    Spec BarSpec `json:"spec"`
    // Status BarStatus `json:"status"`
}
// BarSpec is the spec for a Bar resource
type BarSpec struct {
    DeploymentName string `json:"deploymentName"`
    Image          string `json:"image"`
    Replicas       *int32 `json:"replicas"`
}
// BarStatus is the status for a Bar resource
type BarStatus struct {
    AvailableReplicas int32 `json:"availableReplicas"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// BarList is a list of Bar resources
type BarList struct {
    metav1.TypeMeta `json:",inline" :"metav1.TypeMeta"`
    metav1.ListMeta `json:"metadata" :"metav1.ListMeta"`
    Items []Bar `json:"items" :"items"`
}

register.go顧名思義,就是注冊(cè)資源。

package v1
import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
)
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: "example.com", Version: "v1"}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
    return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
    return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
    // SchemeBuilder initializes a scheme builder
    SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
    // AddToScheme is a global function that registers this API group & version to a scheme
    AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
    scheme.AddKnownTypes(SchemeGroupVersion,
        &Bar{},
        &BarList{},
    )
    metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
    return nil
}

這時(shí)候會(huì)發(fā)現(xiàn)&Bar{},&BarLis{}會(huì)報(bào)錯(cuò),這是因?yàn)槲覀冞€沒有為其實(shí)現(xiàn)deepcopy方法。

由于在自動(dòng)生成代碼的時(shí)候,需要指定header的信息,所以我們?yōu)榱朔奖?,可以?code>code-generator項(xiàng)目下的hack包直接拷貝到我們當(dāng)前項(xiàng)目根目錄下。

接下來我們使用code-generator來為我們自動(dòng)生成代碼:

# 運(yùn)行 code-generator/generate-group.sh
./../../github/code-generator/generate-groups.sh all \
# 指定 group 和 version,生成deeplycopy以及client
operator-test/pkg/client operator-test/pkg/apis crd.example.com:v1 \
# 指定頭文件
--go-header-file=./hack/boilerplate.go.txt \
# 指定輸出位置,默認(rèn)為GOPATH
--output-base ../
Generating deepcopy funcs
Generating clientset for crd.example.com:v1 at operator-test/pkg/client/clientset
Generating listers for crd.example.com:v1 at operator-test/pkg/client/listers
Generating informers for crd.example.com:v1 at operator-test/pkg/client/informers

這時(shí)候我們?cè)賮聿榭错?xiàng)目結(jié)構(gòu):

?  operator-test tree
.
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── pkg
    ├── apis
    │   └── crd.example.com
    │       └── v1
    │           ├── doc.go
    │           ├── register.go
    │           ├── types.go
    │           └── zz_generated.deepcopy.go
    └── client
        ├── clientset
        │   └── versioned
        │       ├── clientset.go
        │       ├── doc.go
        │       ├── fake
        │       │   ├── clientset_generated.go
        │       │   ├── doc.go
        │       │   └── register.go
        │       ├── scheme
        │       │   ├── doc.go
        │       │   └── register.go
        │       └── typed
        │           └── crd.example.com
        │               └── v1
        │                   ├── bar.go
        │                   ├── crd.example.com_client.go
        │                   ├── doc.go
        │                   ├── fake
        │                   │   ├── doc.go
        │                   │   ├── fake_bar.go
        │                   │   └── fake_crd.example.com_client.go
        │                   └── generated_expansion.go
        ├── informers
        │   └── externalversions
        │       ├── crd.example.com
        │       │   ├── interface.go
        │       │   └── v1
        │       │       ├── bar.go
        │       │       └── interface.go
        │       ├── factory.go
        │       ├── generic.go
        │       └── internalinterfaces
        │           └── factory_interfaces.go
        └── listers
            └── crd.example.com
                └── v1
                    ├── bar.go
                    └── expansion_generated.go
22 directories, 29 files

這時(shí)候我們就可以像操作內(nèi)置資源一樣,操作我們的自定義資源了。

我們先準(zhǔn)備crd以及對(duì)應(yīng)的cr,這邊也是可以直接從sample-controller項(xiàng)目進(jìn)行拷貝,做簡(jiǎn)單的修改即可。

# manifests/example.com_bars.yaml
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: (devel)
  creationTimestamp: null
  name: bars.crd.example.com
spec:
  group: crd.example.com
  names:
    kind: Bar
    listKind: BarList
    plural: bars
    singular: bar
  scope: Namespaced
  versions:
  - name: v1
    schema:
      openAPIV3Schema:
        description: Bar is a specification for a Bar resource
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the generated
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: BarSpec is the spec for a Bar resource
            properties:
              deploymentName:
                type: string
              image:
                type: string
              replicas:
                format: int32
                type: integer
            required:
            - deploymentName
            - image
            - replicas
            type: object
        required:
        - spec
        type: object
    served: true
    storage: true
# manifests/cr.yaml
---
apiVersion: crd.example.com/v1
kind: Bar
metadata:
  name: bar-demo
  namespace: default
spec:
  image: "nginx:1.17.1"
  deploymentName: example-bar
  replicas: 2

接下來我們來編寫main函數(shù),這時(shí)候我們就可以使用client-go像操作我們內(nèi)置資源一樣,操作crd資源了。

package main
import (
    "context"
    "fmt"
    v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/tools/cache"
    "k8s.io/client-go/tools/clientcmd"
    "log"
    clientSet "operator-test/pkg/client/clientset/versioned"
    "operator-test/pkg/client/informers/externalversions"
)
func main() {
    config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
    if err != nil {
        log.Fatalln(err)
    }
    clientset, err := clientSet.NewForConfig(config)
    if err != nil {
        log.Fatalln(err)
    }
    list, err := clientset.CrdV1().Bars("default").List(context.TODO(), v1.ListOptions{})
    if err != nil {
        log.Fatalln(err)
    }
    for _, bar := range list.Items {
        fmt.Println(bar.Name)
    }
    factory := externalversions.NewSharedInformerFactory(clientset, 0)
    factory.Crd().V1().Bars().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
        AddFunc:    nil,
        UpdateFunc: nil,
        DeleteFunc: nil,
    })
    // todo
}
// ====
// 程序輸出結(jié)果:
bar-demo

代碼生成tag

在我們上面的示例中,我們?cè)谠创a中添加了很多tag,我們使用這些tag來標(biāo)記一些供生成器使用的屬性。這些tag主要分為兩類:

  • doc.go的package語(yǔ)句智商提供的全局tag
  • 在需要被處理的類型上提供局部tag

tag的使用方法如下所示:

// +tag-name
// 或者
// +tag-name=value

我們可以看到 tag 是通過注釋的形式存在的,另外需要注意的是 tag 的位置非常重要,很多 tag 必須直接位于 type 或 package 語(yǔ)句的上一行,另外一些則必須和 go 語(yǔ)句隔開至少一行空白。

全局tag

必須在目標(biāo)包的doc.go文件中聲明,一般路徑為pkg/apis/<apigroup>/<version>/doc.go,如下所示:

// 為包中任何類型生成深拷貝方法,可以在局部 tag 覆蓋此默認(rèn)行為
// +k8s:deepcopy-gen=package
 
// groupName 指定 API 組的全限定名
// 此 API 組的 v1 版本,放在同一個(gè)包中
// +groupName=crd.example.com
package v1

注意:空行不能省略

局部tag

局部tag要么直接聲明在類型之前,要么位于類型之前的第二個(gè)注釋塊中。下面的 types.go 中聲明了 CR 對(duì)應(yīng)的類型:

// 為當(dāng)前類型生成客戶端,如果不加此注解則無法生成 lister、informer 等包
// +genclient
// 提示此類型不基于 /status 子資源來實(shí)現(xiàn) spec-status 分離,產(chǎn)生的客戶端不具有 UpdateStatus 方法
// 否則,只要類型具有 Status 字段,就會(huì)生成 UpdateStatus 方法
// +genclient:noStatus
// 為每個(gè)頂級(jí) API 類型添加,自動(dòng)生成 DeepCopy 相關(guān)代碼
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// K8S 資源,數(shù)據(jù)庫(kù)
type Database struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`
    Spec DatabaseSpec `json:"spec"`
}
// 不為此類型生成深拷貝方法
// +k8s:deepcopy-gen=false
// 數(shù)據(jù)庫(kù)的規(guī)范
type DatabaseSpec struct {
    User     string `json:"user"`
    Password string `json:"password"`
    Encoding string `json:"encoding,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// 數(shù)據(jù)庫(kù)列表,因?yàn)?list 獲取的是列表,所以需要定義該結(jié)構(gòu)
type DatabaseList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata"`
    Items []Database `json:"items"`
}

在上面 CR 的定義上面就通過 tag 來添加了自動(dòng)生成相關(guān)代碼的一些注釋。此外對(duì)于集群級(jí)別的資源,我們還需要提供如下所示的注釋:

// +genclient:nonNamespaced
// 下面的 Tag 不能少
// +genclient

另外我們還可以控制客戶端提供哪些 HTTP 方法:

// +genclient:noVerbs
// +genclient:onlyVerbs=create,delete
// +genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch
// 僅僅返回 Status 而非整個(gè)資源
// +genclient:method=Create,verb=create,result=k8s.io/apimachinery/pkg/apis/meta/v1.Status
// 下面的 Tag 不能少
// +genclient

使用 tag 定義完需要生成的代碼規(guī)則后,執(zhí)行上面提供的代碼生成腳本即可自動(dòng)生成對(duì)應(yīng)的代碼了。

補(bǔ)充

除了上面介紹的代碼生成方式,我們還可以直接使用sample-controller項(xiàng)目提供的hack/update-condegen.sh腳本。

#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
# 代碼生成器包的位置
CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
# generate-groups.sh <generators> <output-package> <apis-package> <groups-versions>
#                    使用哪些生成器,可選值 deepcopy,defaulter,client,lister,informer,逗號(hào)分隔,all表示全部使用
#                    輸出包的導(dǎo)入路徑  
#                    CR 定義所在路徑
#                    API 組和版本
bash "${CODEGEN_PKG}"/generate-groups.sh "deepcopy,client,informer,lister" \
  k8s.io/sample-controller/pkg/generated k8s.io/sample-controller/pkg/apis \
  samplecontroller:v1alpha1 \
  --output-base "$(dirname "${BASH_SOURCE[0]}")/../../.." \
  --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt
# 自動(dòng)生成的源碼頭部附加的內(nèi)容:
#   --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt

執(zhí)行上面的腳本后,所有 API 代碼會(huì)生成在 pkg/apis 目錄下,clientsets、informers、listers 則生成在 pkg/generated 目錄下。不過從腳本可以看出需要將 code-generator 的包放置到 vendor 目錄下面,現(xiàn)在我們都是使用 go modules 來管理依賴保,我們可以通過執(zhí)行 go mod vendor 命令將依賴包放置到 vendor 目錄下面來。

我們還可以進(jìn)一步提供 hack/verify-codegen.sh 腳本,用于判斷生成的代碼是否 up-to-date:

#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# 先調(diào)用 update-codegen.sh 生成一份新代碼
# 然后對(duì)比新老代碼是否一樣
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
DIFFROOT="${SCRIPT_ROOT}/pkg"
TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
_tmp="${SCRIPT_ROOT}/_tmp"
cleanup() {
  rm -rf "${_tmp}"
}
trap "cleanup" EXIT SIGINT
cleanup
mkdir -p "${TMP_DIFFROOT}"
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
"${SCRIPT_ROOT}/hack/update-codegen.sh"
echo "diffing ${DIFFROOT} against freshly generated codegen"
ret=0
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
if [[ $ret -eq 0 ]]
then
  echo "${DIFFROOT} up to date."
else
  echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
  exit 1
fi

以上就是go語(yǔ)言代碼生成器code generator簡(jiǎn)單介紹的詳細(xì)內(nèi)容,更多關(guān)于go語(yǔ)言code generator的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang與非golang程序探測(cè)beyla源碼解讀

    golang與非golang程序探測(cè)beyla源碼解讀

    這篇文章主要為大家介紹了beyla源碼解讀之golang與非golang程序的探測(cè)實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 利用Go實(shí)現(xiàn)一個(gè)簡(jiǎn)易DAG服務(wù)的示例代碼

    利用Go實(shí)現(xiàn)一個(gè)簡(jiǎn)易DAG服務(wù)的示例代碼

    DAG的全稱是Directed Acyclic Graph,即有向無環(huán)圖,DAG廣泛應(yīng)用于表示具有方向性依賴關(guān)系的數(shù)據(jù),如任務(wù)調(diào)度、數(shù)據(jù)處理流程、項(xiàng)目管理以及許多其他領(lǐng)域,下面,我將用Go語(yǔ)言示范如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的DAG服務(wù),需要的朋友可以參考下
    2024-03-03
  • golang?beego框架環(huán)境搭建過程

    golang?beego框架環(huán)境搭建過程

    這篇文章主要為大家介紹了golang?beego框架環(huán)境搭建的過程腳本,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go設(shè)計(jì)模式之單例模式講解和代碼示例

    Go設(shè)計(jì)模式之單例模式講解和代碼示例

    單例是一種創(chuàng)建型設(shè)計(jì)模式,讓你能夠保證一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)訪問該實(shí)例的全局節(jié)點(diǎn),本文就通過代碼示例給大家講講Go單例模式,需要的朋友可以參考下
    2023-07-07
  • Go 中實(shí)現(xiàn)超時(shí)控制的方案

    Go 中實(shí)現(xiàn)超時(shí)控制的方案

    這篇文章主要介紹了Go 里的超時(shí)控制實(shí)現(xiàn)方案,本文給大家?guī)韮煞N解決方案,第一種方案是 Time.After(d Duration),第二種方案是利用 context,go 的 context 功能強(qiáng)大,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2021-10-10
  • Go Java算法之同構(gòu)字符串示例詳解

    Go Java算法之同構(gòu)字符串示例詳解

    這篇文章主要為大家介紹了Go Java算法之同構(gòu)字符串示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • gorm golang 并發(fā)連接數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法

    gorm golang 并發(fā)連接數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法

    今天小編就為大家分享一篇gorm golang 并發(fā)連接數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • 如何go語(yǔ)言比較兩個(gè)對(duì)象是否深度相同

    如何go語(yǔ)言比較兩個(gè)對(duì)象是否深度相同

    這篇文章主要介紹了如何go語(yǔ)言比較兩個(gè)對(duì)象是否深度相同,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Golang 利用反射對(duì)結(jié)構(gòu)體優(yōu)雅排序的操作方法

    Golang 利用反射對(duì)結(jié)構(gòu)體優(yōu)雅排序的操作方法

    這篇文章主要介紹了Golang 利用反射對(duì)結(jié)構(gòu)體優(yōu)雅排序的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • Go依賴注入DI工具wire使用詳解(golang常用庫(kù)包)

    Go依賴注入DI工具wire使用詳解(golang常用庫(kù)包)

    依賴注入是指程序運(yùn)行過程中,如果需要調(diào)用另一個(gè)對(duì)象協(xié)助時(shí),無須在代碼中創(chuàng)建被調(diào)用者,而是依賴于外部的注入,本文結(jié)合示例代碼給大家介紹Go依賴注入DI工具wire使用,感興趣的朋友一起看看吧
    2022-04-04

最新評(píng)論