最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語(yǔ)言設(shè)計(jì)模式之結(jié)構(gòu)型模式

 更新時(shí)間:2021年06月22日 08:40:02   作者:華為云開(kāi)發(fā)者社區(qū)  
本文主要聚焦在結(jié)構(gòu)型模式(Structural Pattern)上,其主要思想是將多個(gè)對(duì)象組裝成較大的結(jié)構(gòu),并同時(shí)保持結(jié)構(gòu)的靈活和高效,從程序的結(jié)構(gòu)上解決模塊之間的耦合問(wèn)題

一、組合模式(Composite Pattern)

1.1、簡(jiǎn)述

在面向?qū)ο缶幊讨校袃蓚€(gè)常見(jiàn)的對(duì)象設(shè)計(jì)方法,組合和繼承,兩者都可以解決代碼復(fù)用的問(wèn)題,但是使用后者時(shí)容易出現(xiàn)繼承層次過(guò)深,對(duì)象關(guān)系過(guò)于復(fù)雜的副作用,從而導(dǎo)致代碼的可維護(hù)性變差。因此,一個(gè)經(jīng)典的面向?qū)ο笤O(shè)計(jì)原則是:組合優(yōu)于繼承。

我們都知道,組合所表示的語(yǔ)義為“has-a”,也就是部分和整體的關(guān)系,最經(jīng)典的組合模式描述如下:

將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用戶(hù)對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。

Go語(yǔ)言天然就支持了組合模式,而且從它不支持繼承關(guān)系的特點(diǎn)來(lái)看,Go也奉行了組合優(yōu)于繼承的原則,鼓勵(lì)大家在進(jìn)行程序設(shè)計(jì)時(shí)多采用組合的方法。Go實(shí)現(xiàn)組合模式的方式有兩種,分別是直接組合(Direct Composition)和嵌入組合(Embedding Composition),下面我們一起探討這兩種不同的實(shí)現(xiàn)方法。

1.2、Go實(shí)現(xiàn)

直接組合(Direct Composition)的實(shí)現(xiàn)方式類(lèi)似于Java/C++,就是將一個(gè)對(duì)象作為另一個(gè)對(duì)象的成員屬性。

一個(gè)典型的實(shí)現(xiàn)如《使用Go實(shí)現(xiàn)GoF的23種設(shè)計(jì)模式(一)》中所舉的例子,一個(gè)Message結(jié)構(gòu)體,由Header和Body所組成。那么Message就是一個(gè)整體,而Header和Body則為消息的組成部分。

type Message struct {
    Header *Header
    Body   *Body
}

現(xiàn)在,我們來(lái)看一個(gè)稍微復(fù)雜一點(diǎn)的例子,同樣考慮上一篇文章中所描述的插件架構(gòu)風(fēng)格的消息處理系統(tǒng)。前面我們用抽象工廠(chǎng)模式解決了插件加載的問(wèn)題,通常,每個(gè)插件都會(huì)有一個(gè)生命周期,常見(jiàn)的就是啟動(dòng)狀態(tài)和停止?fàn)顟B(tài),現(xiàn)在我們使用組合模式來(lái)解決插件的啟動(dòng)和停止問(wèn)題。

首先給Plugin接口添加幾個(gè)生命周期相關(guān)的方法:

package plugin
...
// 插件運(yùn)行狀態(tài)
type Status uint8

const (
    Stopped Status = iota
    Started
)

type Plugin interface {
  // 啟動(dòng)插件
    Start()
  // 停止插件
    Stop()
  // 返回插件當(dāng)前的運(yùn)行狀態(tài)
    Status() Status
}
// Input、Filter、Output三類(lèi)插件接口的定義跟上一篇文章類(lèi)似
// 這里使用Message結(jié)構(gòu)體替代了原來(lái)的string,使得語(yǔ)義更清晰
type Input interface {
    Plugin
    Receive() *msg.Message
}

type Filter interface {
    Plugin
    Process(msg *msg.Message) *msg.Message
}

type Output interface {
    Plugin
    Send(msg *msg.Message)
}

對(duì)于插件化的消息處理系統(tǒng)而言,一切皆是插件,因此我們將Pipeine也設(shè)計(jì)成一個(gè)插件,實(shí)現(xiàn)Plugin接口:

package pipeline
...
// 一個(gè)Pipeline由input、filter、output三個(gè)Plugin組成
type Pipeline struct {
    status plugin.Status
    input  plugin.Input
    filter plugin.Filter
    output plugin.Output
}

func (p *Pipeline) Exec() {
    msg := p.input.Receive()
    msg = p.filter.Process(msg)
    p.output.Send(msg)
}
// 啟動(dòng)的順序 output -> filter -> input
func (p *Pipeline) Start() {
    p.output.Start()
    p.filter.Start()
    p.input.Start()
    p.status = plugin.Started
    fmt.Println("Hello input plugin started.")
}
// 停止的順序 input -> filter -> output
func (p *Pipeline) Stop() {
    p.input.Stop()
    p.filter.Stop()
    p.output.Stop()
    p.status = plugin.Stopped
    fmt.Println("Hello input plugin stopped.")
}

func (p *Pipeline) Status() plugin.Status {
    return p.status
}

一個(gè)Pipeline由Input、Filter、Output三類(lèi)插件組成,形成了“部分-整體”的關(guān)系,而且它們都實(shí)現(xiàn)了Plugin接口,這就是一個(gè)典型的組合模式的實(shí)現(xiàn)。Client無(wú)需顯式地啟動(dòng)和停止Input、Filter和Output插件,在調(diào)用Pipeline對(duì)象的Start和Stop方法時(shí),Pipeline就已經(jīng)幫你按順序完成對(duì)應(yīng)插件的啟動(dòng)和停止。

相比于上一篇文章,在本文中實(shí)現(xiàn)Input、Filter、Output三類(lèi)插件時(shí),需要多實(shí)現(xiàn)3個(gè)生命周期的方法。還是以上一篇文章中的HelloInput、UpperFilter和ConsoleOutput作為例子,具體實(shí)現(xiàn)如下:

package plugin
...
type HelloInput struct {
    status Status
}

func (h *HelloInput) Receive() *msg.Message {
  // 如果插件未啟動(dòng),則返回nil
    if h.status != Started {
        fmt.Println("Hello input plugin is not running, input nothing.")
        return nil
    }
    return msg.Builder().
        WithHeaderItem("content", "text").
        WithBodyItem("Hello World").
        Build()
}

func (h *HelloInput) Start() {
    h.status = Started
    fmt.Println("Hello input plugin started.")
}

func (h *HelloInput) Stop() {
    h.status = Stopped
    fmt.Println("Hello input plugin stopped.")
}

func (h *HelloInput) Status() Status {
    return h.status
}
package plugin
...
type UpperFilter struct {
    status Status
}

func (u *UpperFilter) Process(msg *msg.Message) *msg.Message {
    if u.status != Started {
        fmt.Println("Upper filter plugin is not running, filter nothing.")
        return msg
    }
    for i, val := range msg.Body.Items {
        msg.Body.Items[i] = strings.ToUpper(val)
    }
    return msg
}

func (u *UpperFilter) Start() {
    u.status = Started
    fmt.Println("Upper filter plugin started.")
}

func (u *UpperFilter) Stop() {
    u.status = Stopped
    fmt.Println("Upper filter plugin stopped.")
}

func (u *UpperFilter) Status() Status {
    return u.status
}

package plugin
...
type ConsoleOutput struct {
    status Status
}

func (c *ConsoleOutput) Send(msg *msg.Message) {
    if c.status != Started {
        fmt.Println("Console output is not running, output nothing.")
        return
    }
    fmt.Printf("Output:\n\tHeader:%+v, Body:%+v\n", msg.Header.Items, msg.Body.Items)
}

func (c *ConsoleOutput) Start() {
    c.status = Started
    fmt.Println("Console output plugin started.")
}

func (c *ConsoleOutput) Stop() {
    c.status = Stopped
    fmt.Println("Console output plugin stopped.")
}

func (c *ConsoleOutput) Status() Status {
    return c.status
}

測(cè)試代碼如下:

package test
...
func TestPipeline(t *testing.T) {
    p := pipeline.Of(pipeline.DefaultConfig())
    p.Start()
    p.Exec()
    p.Stop()
}
// 運(yùn)行結(jié)果
=== RUN   TestPipeline
Console output plugin started.
Upper filter plugin started.
Hello input plugin started.
Pipeline started.
Output:
    Header:map[content:text], Body:[HELLO WORLD]
Hello input plugin stopped.
Upper filter plugin stopped.
Console output plugin stopped.
Hello input plugin stopped.
--- PASS: TestPipeline (0.00s)
PASS

組合模式的另一種實(shí)現(xiàn),嵌入組合(Embedding Composition),其實(shí)就是利用了Go語(yǔ)言的匿名成員特性,本質(zhì)上跟直接組合是一致的。

還是以Message結(jié)構(gòu)體為例,如果采用嵌入組合,則看起來(lái)像是這樣:

type Message struct {
    Header
    Body
}
// 使用時(shí),Message可以引用Header和Body的成員屬性,例如:
msg := &Message{}
msg.SrcAddr = "192.168.0.1"

二、適配器模式(Adapter Pattern)

2.1、簡(jiǎn)述

適配器模式是最常用的結(jié)構(gòu)型模式之一,它讓原本因?yàn)榻涌诓黄ヅ涠鵁o(wú)法一起工作的兩個(gè)對(duì)象能夠一起工作。在現(xiàn)實(shí)生活中,適配器模式也是處處可見(jiàn),比如電源插頭轉(zhuǎn)換器,可以讓英式的插頭工作在中式的插座上。適配器模式所做的就是將一個(gè)接口Adaptee,通過(guò)適配器Adapter轉(zhuǎn)換成Client所期望的另一個(gè)接口Target來(lái)使用,實(shí)現(xiàn)原理也很簡(jiǎn)單,就是Adapter通過(guò)實(shí)現(xiàn)Target接口,并在對(duì)應(yīng)的方法中調(diào)用Adaptee的接口實(shí)現(xiàn)。

一個(gè)典型的應(yīng)用場(chǎng)景是,系統(tǒng)中一個(gè)老的接口已經(jīng)過(guò)時(shí)即將廢棄,但因?yàn)闅v史包袱沒(méi)法立即將老接口全部替換為新接口,這時(shí)可以新增一個(gè)適配器,將老的接口適配成新的接口來(lái)使用。適配器模式很好的踐行了面向?qū)ο笤O(shè)計(jì)原則里的開(kāi)閉原則(open/closed principle),新增一個(gè)接口時(shí)也無(wú)需修改老接口,只需多加一個(gè)適配層即可。

2.2、Go實(shí)現(xiàn)

繼續(xù)考慮上一節(jié)的消息處理系統(tǒng)例子,目前為止,系統(tǒng)的輸入都源自于HelloInput,現(xiàn)在假設(shè)需要給系統(tǒng)新增從Kafka消息隊(duì)列中接收數(shù)據(jù)的功能,其中Kafka消費(fèi)者的接口如下:

package kafka
...
type Records struct {
    Items []string
}

type Consumer interface {
    Poll() Records
}

由于當(dāng)前Pipeline的設(shè)計(jì)是通過(guò)plugin.Input接口來(lái)進(jìn)行數(shù)據(jù)接收,因此kafka.Consumer并不能直接集成到系統(tǒng)中。

怎么辦?使用適配器模式!

為了能讓Pipeline能夠使用kafka.Consumer接口,我們需要定義一個(gè)適配器如下:

package plugin
...
type KafkaInput struct {
    status Status
    consumer kafka.Consumer
}

func (k *KafkaInput) Receive() *msg.Message {
    records := k.consumer.Poll()
    if k.status != Started {
        fmt.Println("Kafka input plugin is not running, input nothing.")
        return nil
    }
    return msg.Builder().
        WithHeaderItem("content", "text").
        WithBodyItems(records.Items).
        Build()
}

// 在輸入插件映射關(guān)系中加入kafka,用于通過(guò)反射創(chuàng)建input對(duì)象
func init() {
    inputNames["hello"] = reflect.TypeOf(HelloInput{})
    inputNames["kafka"] = reflect.TypeOf(KafkaInput{})
}
...

因?yàn)镚o語(yǔ)言并沒(méi)有構(gòu)造函數(shù),如果按照上一篇文章中的抽象工廠(chǎng)模式來(lái)創(chuàng)建KafkaInput,那么得到的實(shí)例中的consumer成員因?yàn)闆](méi)有被初始化而會(huì)是nil。因此,需要給Plugin接口新增一個(gè)Init方法,用于定義插件的一些初始化操作,并在工廠(chǎng)返回實(shí)例前調(diào)用。

package plugin
...
type Plugin interface {
    Start()
    Stop()
    Status() Status
    // 新增初始化方法,在插件工廠(chǎng)返回實(shí)例前調(diào)用
    Init()
}

// 修改后的插件工廠(chǎng)實(shí)現(xiàn)如下
func (i *InputFactory) Create(conf Config) Plugin {
    t, _ := inputNames[conf.Name]
    p := reflect.New(t).Interface().(Plugin)
  // 返回插件實(shí)例前調(diào)用Init函數(shù),完成相關(guān)初始化方法
    p.Init()
    return p
}

// KakkaInput的Init函數(shù)實(shí)現(xiàn)
func (k *KafkaInput) Init() {
    k.consumer = &kafka.MockConsumer{}
}

上述代碼中的kafka.MockConsumer為我們模式Kafka消費(fèi)者的一個(gè)實(shí)現(xiàn),代碼如下:

package kafka
...
type MockConsumer struct {}

func (m *MockConsumer) Poll() *Records {
    records := &Records{}
    records.Items = append(records.Items, "i am mock consumer.")
    return records
}

測(cè)試代碼如下:

package test
...
func TestKafkaInputPipeline(t *testing.T) {
    config := pipeline.Config{
        Name: "pipeline2",
        Input: plugin.Config{
            PluginType: plugin.InputType,
            Name:       "kafka",
        },
        Filter: plugin.Config{
            PluginType: plugin.FilterType,
            Name:       "upper",
        },
        Output: plugin.Config{
            PluginType: plugin.OutputType,
            Name:       "console",
        },
    }
    p := pipeline.Of(config)
    p.Start()
    p.Exec()
    p.Stop()
}
// 運(yùn)行結(jié)果
=== RUN   TestKafkaInputPipeline
Console output plugin started.
Upper filter plugin started.
Kafka input plugin started.
Pipeline started.
Output:
    Header:map[content:kafka], Body:[I AM MOCK CONSUMER.]
Kafka input plugin stopped.
Upper filter plugin stopped.
Console output plugin stopped.
Pipeline stopped.
--- PASS: TestKafkaInputPipeline (0.00s)
PASS

三、橋接模式(Bridge Pattern)

3.1、簡(jiǎn)述

橋接模式主要用于將抽象部分和實(shí)現(xiàn)部分進(jìn)行解耦,使得它們能夠各自往獨(dú)立的方向變化。它解決了在模塊有多種變化方向的情況下,用繼承所導(dǎo)致的類(lèi)爆炸問(wèn)題。舉一個(gè)例子,一個(gè)產(chǎn)品有形狀和顏色兩個(gè)特征(變化方向),其中形狀分為方形和圓形,顏色分為紅色和藍(lán)色。如果采用繼承的設(shè)計(jì)方案,那么就需要新增4個(gè)產(chǎn)品子類(lèi):方形紅色、圓形紅色、方形藍(lán)色、圓形紅色。如果形狀總共有m種變化,顏色有n種變化,那么就需要新增m*n個(gè)產(chǎn)品子類(lèi)!現(xiàn)在我們使用橋接模式進(jìn)行優(yōu)化,將形狀和顏色分別設(shè)計(jì)為一個(gè)抽象接口獨(dú)立出來(lái),這樣需要新增2個(gè)形狀子類(lèi):方形和圓形,以及2個(gè)顏色子類(lèi):紅色和藍(lán)色。同樣,如果形狀總共有m種變化,顏色有n種變化,總共只需要新增m+n個(gè)子類(lèi)!

上述例子中,我們通過(guò)將形狀和顏色抽象為一個(gè)接口,使產(chǎn)品不再依賴(lài)于具體的形狀和顏色細(xì)節(jié),從而達(dá)到了解耦的目的。橋接模式本質(zhì)上就是面向接口編程,可以給系統(tǒng)帶來(lái)很好的靈活性和可擴(kuò)展性。如果一個(gè)對(duì)象存在多個(gè)變化的方向,而且每個(gè)變化方向都需要擴(kuò)展,那么使用橋接模式進(jìn)行設(shè)計(jì)那是再合適不過(guò)了。

3.2、Go實(shí)現(xiàn)

回到消息處理系統(tǒng)的例子,一個(gè)Pipeline對(duì)象主要由Input、Filter、Output三類(lèi)插件組成(3個(gè)特征),因?yàn)槭遣寮南到y(tǒng),不可避免的就要求支持多種Input、Filter、Output的實(shí)現(xiàn),并能夠靈活組合(有多個(gè)變化的方向)。顯然,Pipeline就非常適合使用橋接模式進(jìn)行設(shè)計(jì),實(shí)際上我們也這么做了。我們將Input、Filter、Output分別設(shè)計(jì)成一個(gè)抽象的接口,它們按照各自的方向去擴(kuò)展。Pipeline只依賴(lài)的這3個(gè)抽象接口,并不感知具體實(shí)現(xiàn)的細(xì)節(jié)。

package plugin
...
type Input interface {
    Plugin
    Receive() *msg.Message
}

type Filter interface {
    Plugin
    Process(msg *msg.Message) *msg.Message
}

type Output interface {
    Plugin
    Send(msg *msg.Message)
}
package pipeline
...
// 一個(gè)Pipeline由input、filter、output三個(gè)Plugin組成
type Pipeline struct {
    status plugin.Status
    input  plugin.Input
    filter plugin.Filter
    output plugin.Output
}
// 通過(guò)抽象接口來(lái)使用,看不到底層的實(shí)現(xiàn)細(xì)節(jié)
func (p *Pipeline) Exec() {
    msg := p.input.Receive()
    msg = p.filter.Process(msg)
    p.output.Send(msg)
}

測(cè)試代碼如下:

package test
...
func TestPipeline(t *testing.T) {
    p := pipeline.Of(pipeline.DefaultConfig())
    p.Start()
    p.Exec()
    p.Stop()
}
// 運(yùn)行結(jié)果
=== RUN   TestPipeline
Console output plugin started.
Upper filter plugin started.
Hello input plugin started.
Pipeline started.
Output:
    Header:map[content:text], Body:[HELLO WORLD]
Hello input plugin stopped.
Upper filter plugin stopped.
Console output plugin stopped.
Pipeline stopped.
--- PASS: TestPipeline (0.00s)
PASS

四、總結(jié)

本文主要介紹了結(jié)構(gòu)型模式中的組合模式、適配器模式和橋接模式。組合模式主要解決代碼復(fù)用的問(wèn)題,相比于繼承關(guān)系,組合模式可以避免繼承層次過(guò)深導(dǎo)致的代碼復(fù)雜問(wèn)題,因此面向?qū)ο笤O(shè)計(jì)領(lǐng)域流傳著組合優(yōu)于繼承的原則,而Go語(yǔ)言的設(shè)計(jì)也很好實(shí)踐了該原則;適配器模式可以看作是兩個(gè)不兼容接口之間的橋梁,可以將一個(gè)接口轉(zhuǎn)換成Client所希望的另外一個(gè)接口,解決了模塊之間因?yàn)榻涌诓患嫒荻鵁o(wú)法一起工作的問(wèn)題;橋接模式將模塊的抽象部分和實(shí)現(xiàn)部分進(jìn)行分離,讓它們能夠往各自的方向擴(kuò)展,從而達(dá)到解耦的目的。

以上就是Go語(yǔ)言設(shè)計(jì)模式之結(jié)構(gòu)型模式的詳細(xì)內(nèi)容,更多關(guān)于Go結(jié)構(gòu)型模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang validator參數(shù)校驗(yàn)的實(shí)現(xiàn)

    golang validator參數(shù)校驗(yàn)的實(shí)現(xiàn)

    這篇文章主要介紹了golang validator參數(shù)校驗(yàn)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 對(duì)Golang import 導(dǎo)入包語(yǔ)法詳解

    對(duì)Golang import 導(dǎo)入包語(yǔ)法詳解

    今天小編就為大家分享一篇對(duì)Golang import 導(dǎo)入包語(yǔ)法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • 三種Golang數(shù)組拷貝的實(shí)現(xiàn)方式與性能分析

    三種Golang數(shù)組拷貝的實(shí)現(xiàn)方式與性能分析

    在?Golang?中,有多種方式可以進(jìn)行數(shù)組的拷貝,本文將對(duì)其中的三種方式進(jìn)行性能分析,并比較它們的優(yōu)缺點(diǎn),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-06-06
  • 使用Go語(yǔ)言提高圖片分辨率的方法與實(shí)踐

    使用Go語(yǔ)言提高圖片分辨率的方法與實(shí)踐

    在圖像處理和計(jì)算機(jī)視覺(jué)領(lǐng)域,提高圖片分辨率是一個(gè)常見(jiàn)的問(wèn)題,隨著高分辨率顯示設(shè)備的普及,如4K、8K電視以及高像素手機(jī)攝像頭的應(yīng)用,用戶(hù)對(duì)高質(zhì)量圖片的需求也越來(lái)越高,本文將介紹使用Golang語(yǔ)言提高圖片分辨率的方法與實(shí)踐,需要的朋友可以參考下
    2023-12-12
  • golang網(wǎng)絡(luò)socket粘包問(wèn)題的解決方法

    golang網(wǎng)絡(luò)socket粘包問(wèn)題的解決方法

    這篇文章主要介紹了golang網(wǎng)絡(luò)socket粘包問(wèn)題的解決方法,簡(jiǎn)單講述了socket粘包的定義并結(jié)合實(shí)例形式分析了Go語(yǔ)言解決粘包問(wèn)題的方法,需要的朋友可以參考下
    2016-07-07
  • Go?Interface接口初學(xué)者手冊(cè)

    Go?Interface接口初學(xué)者手冊(cè)

    這篇文章主要為大家介紹了Go?Interface接口的基礎(chǔ)用法實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go 并發(fā)讀寫(xiě) sync.map 詳細(xì)

    Go 并發(fā)讀寫(xiě) sync.map 詳細(xì)

    閱讀本文你將會(huì)明確 sync.Map 和原生 map +互斥鎖/讀寫(xiě)鎖之間的性能情況。標(biāo)準(zhǔn)庫(kù) sync.Map 雖說(shuō)支持并發(fā)讀寫(xiě) map,但更適用于讀多寫(xiě)少的場(chǎng)景,因?yàn)樗麑?xiě)入的性能比較差,使用時(shí)要考慮清楚這一點(diǎn)。
    2021-10-10
  • docker如何安裝部署golang應(yīng)用程序

    docker如何安裝部署golang應(yīng)用程序

    這篇文章主要為大家介紹了docker如何安裝部署golang應(yīng)用程序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Go語(yǔ)言編譯程序從后臺(tái)運(yùn)行,不出現(xiàn)dos窗口的操作

    Go語(yǔ)言編譯程序從后臺(tái)運(yùn)行,不出現(xiàn)dos窗口的操作

    這篇文章主要介紹了Go語(yǔ)言編譯程序從后臺(tái)運(yùn)行,不出現(xiàn)dos窗口的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • go使用Viper管理配置文件的方法步驟

    go使用Viper管理配置文件的方法步驟

    在項(xiàng)目開(kāi)發(fā)中,需要把一些配置配置提取出來(lái),方便配置和管理,可以使用Viper工具,Viper 是 Go 應(yīng)用程序的完整配置解決方案,也支持從環(huán)境變量中讀取,本文給大家介紹了go使用Viper管理配置文件的方法步驟,需要的朋友可以參考下
    2024-07-07

最新評(píng)論

昭通市| 二连浩特市| 巴青县| 玉环县| 客服| 宽甸| 宾川县| 炉霍县| 武威市| 辉南县| 安平县| 彝良县| 六安市| 观塘区| 韶山市| 龙游县| 隆回县| 邮箱| 浙江省| 宁安市| 宁国市| 大兴区| 嫩江县| 平遥县| 溧阳市| 巩义市| 石首市| 南郑县| 布拖县| 阿拉尔市| 哈尔滨市| 梁平县| 新丰县| 汝州市| 房山区| 广东省| 衢州市| 张家川| 军事| 南和县| 文安县|