成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

go語(yǔ)言解析yaml go語(yǔ)言解析注釋

C語(yǔ)言操作yaml配置文件通用操作工具

在go語(yǔ)言中使用viper之類的庫(kù)很方便的處理yaml配置文件,但是在c語(yǔ)言中就比較麻煩,經(jīng)過(guò)一番思索和借助強(qiáng)大的github,發(fā)現(xiàn)了一個(gè)libyaml c庫(kù),但是網(wǎng)上的例子都比較麻煩,而且比較繁瑣,就想法作了一個(gè)相對(duì)比較容易配置的解析應(yīng)用,可以簡(jiǎn)單地類似viper 的模式進(jìn)行配置實(shí)現(xiàn)不同的配置文件讀取。如你的配置文件很復(fù)雜請(qǐng)按格式修改KeyValue 全局變量,歡迎大家一起完善

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供杭錦后網(wǎng)站建設(shè)、杭錦后做網(wǎng)站、杭錦后網(wǎng)站設(shè)計(jì)、杭錦后網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、杭錦后企業(yè)網(wǎng)站模板建站服務(wù),十年杭錦后做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

庫(kù)請(qǐng)自行下載 GitHub - yaml/libyaml: Canonical source repository for LibYAML

直接上代碼

yaml示例文件

%YAML 1.1

---

mqtt:

subtopic: "Control/#"

pubtopic: "bbt"

qos: 1

serveraddress: "tcp://192.168.0.25:1883"

clientid: "kvm_test"

writelog: false

writetodisk: false

outputfile: "./receivedMessages.txt"

hearttime: 30

#ifndef __CONFIG_H__

#define __CONFIG_H__

#ifdef __cplusplus

extern "C" {

#endif

/************************/

/* Minimum YAML version */

/************************/

#define YAML_VERSION_MAJOR 1

#define YAML_VERSION_MINOR 1

#define STRUCT_TYPE_NAME 100

#define INT_TYPE_NAME 101

#define STRING_TYPE_NAME 102

#define BOOL_TYPE_NAME 103

#define FLOAT_TYPE_NAME 104

#define MAP_TYPE_NAME 105

#define LIST_TYPE_NAME 106

typedef struct{

char *key;

void *value;

int valuetype;

char *parent;

}KeyValue,*pKeyValue;

#ifdef __cplusplus

}

#endif

#endif

#include

#include

#include

#include

#include

#include

#include

#include "config.h"

typedef struct {

char *SUBTOPIC; //string `yaml:"subtopic" mapstructure:"subtopic"` //"topic1"

char *PUBTOPIC; //string `yaml:"pubtopic" mapstructure:"pubtopic"`

int QOS; //byte `yaml:"qos" mapstructure:"qos"` //1

char *SERVERADDRESS; //string `yaml:"serveraddress" mapstructure:"serveraddress"` //= "tcp://mosquitto:1883"

char *CLIENTID; //string `yaml:"clientid" mapstructure:"clientid"` //= "mqtt_subscriber"

int HEARTTIME; //int `yaml:"hearttime" mapstructure:"hearttime"`

// CommandLocalPath string `yam:"commanlocalpath"`

}mqttSection,*pmqttSection;

typedef struct {

mqttSection Mqtt;// `yaml:"mqtt" mapstructure:"mqtt"`

// KVM kvmSection `yaml:"kvm" mapstructure:"kvm"`

}ConfigT;

ConfigT config;

static KeyValue webrtcconfig[]={

{"mqtt",config,STRUCT_TYPE_NAME,NULL},

{"subtopic",(config.Mqtt.SUBTOPIC),STRING_TYPE_NAME,"mqtt"},

{"pubtopic",(config.Mqtt.PUBTOPIC),STRING_TYPE_NAME,"mqtt"},

{"qos",(config.Mqtt.QOS),INT_TYPE_NAME,"mqtt"},

{"serveraddress",(config.Mqtt.SERVERADDRESS),STRING_TYPE_NAME,"mqtt"},

{"clientid",(config.Mqtt.CLIENTID),STRING_TYPE_NAME,"mqtt"},

{"hearttime",(config.Mqtt.HEARTTIME),INT_TYPE_NAME,"mqtt"},

{NULL,NULL,0,NULL},

};

int printConfig(ConfigT * pconfig){

if(pconfig==NULL) return -1;

printf("mqtt:r ");

if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf("subtopic: %sr ",pconfig-Mqtt.SUBTOPIC); }

if(pconfig-Mqtt.SUBTOPIC!=NULL) {printf("pubtopic: %sr ",pconfig-Mqtt.PUBTOPIC); }

printf("qos: %dr ",config.Mqtt.QOS);

if(pconfig-Mqtt.SERVERADDRESS!=NULL) {printf("serveraddress: %sr ",pconfig-Mqtt.SERVERADDRESS); }

if(pconfig-Mqtt.CLIENTID!=NULL) {printf("clientid: %sr ",pconfig-Mqtt.CLIENTID); }

printf("hearttime: %dr ",config.Mqtt.HEARTTIME);

}

int freeConfig(ConfigT * pconfig){

if(pconfig==NULL) return -1;

if(pconfig-Mqtt.SERVERADDRESS!=NULL) {free(pconfig-Mqtt.SERVERADDRESS); }

if(pconfig-Mqtt.CLIENTID!=NULL) {free(pconfig-Mqtt.CLIENTID); }

if(pconfig-Mqtt.SUBTOPIC!=NULL) {free(pconfig-Mqtt.SUBTOPIC); }

}

char currentkey[100];

void getvalue(yaml_event_t event,pKeyValue *ppconfigs){

char *value = (char *)event.data.scalar.value;

pKeyValue pconfig=*ppconfigs;

char *pstringname;

while(pconfig-key!=NULL){

if(currentkey[0]!=0){

if(!strcmp(currentkey,pconfig-key))

{

switch(pconfig-valuetype){

case STRING_TYPE_NAME:

pstringname=strdup(value);

printf("get string value %sr ",pstringname);

*((char**)pconfig-value)=pstringname;

memset(currentkey, 0, sizeof(currentkey));

break;

case INT_TYPE_NAME:

*((int*)(pconfig-value))=atoi(value);

memset(currentkey, 0, sizeof(currentkey));

break;

case BOOL_TYPE_NAME:

if(!strcmp(value,"true")) *((bool*)(pconfig-value))=true;

else *((bool*)(pconfig-value))=false;

memset(currentkey, 0, sizeof(currentkey));

break;

case FLOAT_TYPE_NAME:

*((float*)(pconfig-value))=atof(value);

memset(currentkey, 0, sizeof(currentkey));

break;

case STRUCT_TYPE_NAME:

case MAP_TYPE_NAME:

case LIST_TYPE_NAME:

memset(currentkey, 0, sizeof(currentkey));

strncpy(currentkey,value,strlen(value));

break;

default:

break;

}

break;

}

//continue;

}else{

if(!strcmp(value,pconfig-key)){

strncpy(currentkey,pconfig-key,strlen(pconfig-key));

break;

}

}

pconfig++;

}

}

int Load_YAML_Config( char *yaml_file, KeyValue *(configs[]) )

{

struct stat filecheck;

yaml_parser_t parser;

yaml_event_t event;

bool done = 0;

unsigned char type = 0;

unsigned char sub_type = 0;

if (stat(yaml_file, filecheck) != false )

{

printf("[%s, line %d] Cannot open configuration file '%s'! %s", __FILE__, __LINE__, yaml_file, strerror(errno) );

return -1;

}

FILE *fh = fopen(yaml_file, "r");

if (!yaml_parser_initialize(parser))

{

printf("[%s, line %d] Failed to initialize the libyaml parser. Abort!", __FILE__, __LINE__);

return -1;

}

if (fh == NULL)

{

printf("[%s, line %d] Failed to open the configuration file '%s' Abort!", __FILE__, __LINE__, yaml_file);

return -1;

}

memset(currentkey, 0, sizeof(currentkey));

/* Set input file */

yaml_parser_set_input_file(parser, fh);

while(!done)

{

if (!yaml_parser_parse(parser, event))

{

/* Useful YAML vars: parser.context_mark.line+1, parser.context_mark.column+1, parser.problem, parser.problem_mark.line+1, parser.problem_mark.column+1 */

printf( "[%s, line %d] libyam parse error at line %ld in '%s'", __FILE__, __LINE__, parser.problem_mark.line+1, yaml_file);

}

if ( event.type == YAML_DOCUMENT_START_EVENT )

{

//yaml file first line is version

//%YAML 1.1

//---

yaml_version_directive_t *ver = event.data.document_start.version_directive;

if ( ver == NULL )

{

printf( "[%s, line %d] Invalid configuration file. Configuration must start with "%%YAML 1.1"", __FILE__, __LINE__);

}

int major = ver-major;

int minor = ver-minor;

if (! (major == YAML_VERSION_MAJOR minor == YAML_VERSION_MINOR) )

{

printf( "[%s, line %d] Configuration has a invalid YAML version. Must be 1.1 or above", __FILE__, __LINE__);

return -1;

}

}

else if ( event.type == YAML_STREAM_END_EVENT )

{

done = true;

}

else if ( event.type == YAML_MAPPING_END_EVENT )

{

sub_type = 0;

}

else if ( event.type == YAML_SCALAR_EVENT )

{

getvalue(event,configs);

}

}

return 0;

}

int main(int argc, char *argv[]){

pKeyValue pconfig=webrtcconfig[0];

Load_YAML_Config("../../etc/kvmagent.yml",pconfig);

printConfig(config);

freeConfig(config);

}

Golang項(xiàng)目中引入yaml.v2配置文件

在Go語(yǔ)言項(xiàng)目中,常用的配置文件yaml、toml、json、xml、ini幾種,因?yàn)楸菊轮饕v解yaml配置文件的使用方法,其他幾種配置文件在這里就不展開了介紹了,大家有興趣可以自行百度。

yaml文件的語(yǔ)法網(wǎng)上有很多的教程,大家自行百度,這里也推薦兩個(gè)鏈接:

yaml文件解析使用的是github上第三方開源框架 gopkg.in/yaml.v2 ,下面詳細(xì)介紹安裝和使用的方法:

參考鏈接:

從PHP 到Golang 的筆記 ( 轉(zhuǎn) )

———文章來(lái)源 YamiOdymel/PHP-to-Golang

PHP和模塊之間的關(guān)系令人感到煩躁,假設(shè)你要讀取 yaml 檔案,你需要有一個(gè) yaml 的模塊,為此,你還需要將其編譯然后將編譯后的模塊擺放至指定位置,之后換了一臺(tái)伺服器你還要重新編譯,這點(diǎn)到現(xiàn)在還是沒有改善;順帶一提之后出了PHP 7效能確實(shí)提升了許多(比Python 3快了些),但PHP仍令我感到臃腫,我覺得是時(shí)候

(轉(zhuǎn)行)了。

PHP 和Golang 的效能我想毋庸置疑是后者比較快(而且是以倍數(shù)來(lái)算),也許有的人會(huì)認(rèn)為兩種不應(yīng)該被放在一起比較,但Golang 本身就是偏向Web 開發(fā)的,所以這也是為什么我考慮轉(zhuǎn)用Golang 的原因,起初我的考慮有幾個(gè):Node.js 和Rust 還有最終被選定的Golang;先談?wù)凬ode.js 吧。

Node.js的效能可以說(shuō)是快上PHP 3.5倍至6倍左右 ,而且撰寫的語(yǔ)言還是JavaScript,蒸蚌,如此一來(lái)就不需要學(xué)習(xí)新語(yǔ)言了!搭配Babel更可以說(shuō)是萬(wàn)能,不過(guò)那跟「跳跳虎」一樣的Async邏輯還有那恐怖的Callback Hell,有人認(rèn)為前者是種優(yōu)點(diǎn),這點(diǎn)我不否認(rèn),但是對(duì)學(xué)習(xí)PHP的我來(lái)說(shuō)太過(guò)于"Mind Fuck",至于后者的Callback Hell雖然有Promise,但是那又是另一個(gè)「Then Hell」的故事了。相較于Golang之下,Node.js似乎就沒有那么吸引我了。你確實(shí)可以用Node.js寫出很多東西,不過(guò)那V8引擎的效能仍然有限,而且要學(xué)習(xí)新的事物,不就應(yīng)該是「全新」的嗎;)?

題外話: 為什么Node.js不適合大型和商業(yè)專案?

在拋棄改用Node.js 之后我曾經(jīng)花了一天的時(shí)間嘗試Rust 和Iron 框架,嗯??Rust 太強(qiáng)大了,強(qiáng)大到讓我覺得Rust 不應(yīng)該用在這里,這想法也許很蠢,但Rust 讓我覺得適合更應(yīng)該拿來(lái)用在系統(tǒng)或者是部分底層的地方,而不應(yīng)該是網(wǎng)路服務(wù)。

Golang是我最終的選擇,主要在于我花了一天的時(shí)間來(lái)研究的時(shí)候意外地發(fā)現(xiàn)Golang夭壽簡(jiǎn)潔( 關(guān)鍵字只有25個(gè) ),相較之下Rust太過(guò)于「強(qiáng)大」令我怯步;而且Golang帶有許多工具,例如 go fmt 會(huì)自動(dòng)幫你整理程式碼、 go doc 會(huì)自動(dòng)幫你生產(chǎn)文件、 go test 可以自動(dòng)單元測(cè)試并生產(chǎn)覆蓋率報(bào)表、也有 go get 套件管理工具(雖然沒有版本功能),不過(guò)都很實(shí)用,而且也不需要加上分號(hào)( ; ),真要說(shuō)不好的地方??大概就是強(qiáng)迫你花括號(hào)不能換行放吧(沒錯(cuò),我就是花括號(hào)會(huì)換行放的人)。

當(dāng)我在撰寫這份文件的時(shí)候 我會(huì)先假設(shè)你有一定的基礎(chǔ) ,你可以先閱讀下列的手冊(cè),他們都很不錯(cuò)。

你能夠在PHP 里面想建立一個(gè)變數(shù)的時(shí)候就直接建立,夭壽贊,是嗎?

蒸蚌!那么Golang 呢?在Golang 中變數(shù)分為幾類:「新定義」、「預(yù)先定義」、「自動(dòng)新定義」、「覆蓋」。讓我們來(lái)看看范例:

在PHP中你會(huì)很常用到 echo 來(lái)顯示文字,像這樣。

然而在Golang中你會(huì)需要 fmt 套件,關(guān)于「什么是套件」的說(shuō)明你可以在文章下述了解。

這很簡(jiǎn)單,而且兩個(gè)語(yǔ)言的用法相差甚少,下面這是PHP:

只是Golang 稍微聒噪了一點(diǎn),你必須在函式后面宣告他最后會(huì)回傳什么資料型別。

在PHP 中你要回傳多個(gè)資料你就會(huì)用上陣列,然后將資料放入陣列里面,像這樣。

然而在Golang 中你可以不必用到一個(gè)陣列,函式可以一次回傳多個(gè)值:

兩個(gè)語(yǔ)言的撰寫方式不盡相同。

主要是PHP 的陣列能做太多事情了,所以在PHP 里面要儲(chǔ)存什么用陣列就好了。

在Golang里??沒有這么萬(wàn)能的東西,首先要先了解Golang中有這些型態(tài): array , slice , map , interface ,

你他媽的我到底看了三洨,首先你要知道Golang是個(gè)強(qiáng)型別語(yǔ)言,意思是你的陣列中 只能有一種型態(tài) ,什么意思?當(dāng)你決定這個(gè)陣列是用來(lái)擺放字串資料的時(shí)候,你就只能在里面放字串。沒有數(shù)值、沒有布林值,就像你沒有女朋友一樣。

先撇開PHP 的「萬(wàn)能陣列」不管,Golang 中的陣列既單純卻又十分腦殘,在定義一個(gè)陣列的時(shí)候,你必須給他一個(gè)長(zhǎng)度還有其內(nèi)容存放的資料型態(tài),你的陣列內(nèi)容不一定要填滿其長(zhǎng)度,但是你的陣列內(nèi)容不能超過(guò)你當(dāng)初定義的長(zhǎng)度。

切片??這聽起來(lái)也許很奇怪,但是你確實(shí)可以「切」他,讓我們先談?wù)劇盖衅贡绕稹戈嚵小挂迷谀睦铮骸改悴挥枚x其最大長(zhǎng)度,而且你可以直接賦予值」,沒了。

我們剛才有提到你可以「切」他,記得嗎?這有點(diǎn)像是PHP中的 array_slice() ,但是Golang直接讓Slice「內(nèi)建」了這個(gè)用法,其用法是: slice[開始:結(jié)束] 。

在PHP中倒是沒有那么方便,在下列PHP范例中你需要不斷地使用 array_slice() 。

你可以把「映照」看成是一個(gè)有鍵名和鍵值的陣列,但是記?。骸改阈枰孪榷x其鍵名、鍵值的資料型態(tài)」,這仍限制你沒辦法在映照中存放多種不同型態(tài)的資料。

在Golang里可就沒這么簡(jiǎn)單了,你需要先用 make() 宣告 map 。

也許你不喜歡「接口」這個(gè)詞,但用「介面」我怕會(huì)誤導(dǎo)大眾,所以,是的,接下來(lái)我會(huì)繼續(xù)稱其為「接口」。還記得你可以在PHP 的關(guān)聯(lián)陣列里面存放任何型態(tài)的資料嗎,像下面這樣?

現(xiàn)在你有福了!正因?yàn)镚olang中的 interface{} 可以接受任何內(nèi)容,所以你可以把它拿來(lái)存放任何型態(tài)的資料。

有時(shí)候你也許會(huì)有個(gè)不定值的變數(shù),在PHP 里你可以直接將一個(gè)變數(shù)定義成字串、數(shù)值、空值、就像你那變心的女友一樣隨時(shí)都在變。

在Golang中你必須給予變數(shù)一個(gè)指定的資料型別,不過(guò)還記得剛才提到的:「Golang中有個(gè) interface{} 能夠 存放任何事物 」嗎( 雖然也不是真的任何事物啦?? )?

當(dāng)我們程式中不需要繼續(xù)使用到某個(gè)資源或是發(fā)生錯(cuò)誤的時(shí)候,我們索性會(huì)將其關(guān)閉或是拋棄來(lái)節(jié)省資源開銷,例如PHP 里的讀取檔案:

在Golang中,你可以使用 defer 來(lái)在函式結(jié)束的時(shí)候自動(dòng)執(zhí)行某些程式(其執(zhí)行方向?yàn)榉聪?。所以你就不需要在函式最后面結(jié)束最前面的資源。

defer 可以被稱為「推遲執(zhí)行」,實(shí)際上就是在函式結(jié)束后會(huì)「反序」執(zhí)行的東西,例如你按照了這樣的順序定義 defer : A-B-C-D ,那么執(zhí)行的順序其實(shí)會(huì)是 D-C-B-A ,這用在程式結(jié)束時(shí)還蠻有用的,讓我們看看Golang如何改善上述范例。

這東西很邪惡,不是嗎?又不是在寫B(tài)ASIC,不過(guò)也許有時(shí)候你會(huì)在PHP 用上呢。但是拜托,不要。

Golang中僅有 for 一種回圈但卻能夠達(dá)成 foreach 、 while 、 for 多種用法。普通 for 回圈寫法在兩個(gè)語(yǔ)言中都十分相近。

在Golang請(qǐng)記得:如果你的 i 先前并不存在,那么你就需要定義它,所以下面這個(gè)范例你會(huì)看見 i := 0 。

在PHP里, foreach() 能夠直接給你值和鍵名,用起來(lái)十分簡(jiǎn)單。

Golang里面雖然僅有 for() 但卻可以使用 range 達(dá)成和PHP一樣的 foreach 方式。

一個(gè) while(條件) 回圈在PHP里面可以不斷地執(zhí)行區(qū)塊中的程式,直到 條件 為 false 為止。

在Golang里也有相同的做法,但仍是透過(guò) for 回圈,請(qǐng)注意這個(gè) for 回圈并沒有任何的分號(hào)( ; ),而且一個(gè)沒有條件的 for 回圈會(huì)一直被執(zhí)行。

PHP中有 do .. while() 回圈可以先做區(qū)塊中的動(dòng)作。

在Golang中則沒有相關(guān)函式,但是你可以透過(guò)一個(gè)無(wú)止盡的 for 回圈加上條件式來(lái)讓他結(jié)束回圈。

要是你真的希望完全符合像是PHP那樣的設(shè)計(jì)方式,或者你可以在Golang中使用很邪惡的 goto 。

在PHP中我們可以透過(guò) date() 像這樣取得目前的日期。

在Golang就稍微有趣點(diǎn)了,因?yàn)镚olang中并不是以 Y-m-d 這種格式做為定義,而是 1 、 2 、 3 ,這令你需要去翻閱文件,才能夠知道 1 的定義是代表什么。

俗話說(shuō):「爆炸就是藝術(shù)」,可愛的PHP用詞真的很大膽,像是: explode() (爆炸)、 die() (死掉),回歸正傳,如果你想在PHP里面將字串切割成陣列,你可以這么做。

簡(jiǎn)單的就讓一個(gè)字串給「爆炸」了,那么Golang 呢?

對(duì)了,記得引用 strings 套件。

這真的是很常用到的功能,就像物件一樣有著鍵名和鍵值,在PHP 里面你很簡(jiǎn)單的就能靠陣列(Array)辦到。

真是太棒了,那么Golang呢?用 map 是差不多啦。如果有必要的話,你可以稍微復(fù)習(xí)一下先前提到的「多資料儲(chǔ)存型態(tài)-Stores」。

你很常會(huì)在PHP里面用 isset() 檢查一個(gè)索引是否存在,不是嗎?

在Golang里面很簡(jiǎn)單的能夠這樣辦到(僅適用于 map )。

指針(有時(shí)也做參照)是一個(gè)像是「變數(shù)別名」的方法,這種方法讓你不用整天覆蓋舊的變數(shù),讓我們假設(shè) A = 1; B = A; 這個(gè)時(shí)候 B 會(huì)復(fù)制一份 A 且兩者不相干,倘若你希望修改 B 的時(shí)候?qū)嶋H上也會(huì)修改到 A 的值,就會(huì)需要指針。

指針比起復(fù)制一個(gè)變數(shù),他會(huì)建立一個(gè)指向到某個(gè)變數(shù)的記憶體位置,這也就是為什么你改變指針,實(shí)際上是在改變某個(gè)變數(shù)。

在Golang你需要用上 * 還有 符號(hào)。

有些時(shí)候你會(huì)回傳一個(gè)陣列,這個(gè)陣列里面可能有資料還有錯(cuò)誤代號(hào),而你會(huì)用條件式判斷錯(cuò)誤代號(hào)是否非空值。

在Golang中函式可以一次回傳多個(gè)值。為此,你不需要真的回傳一個(gè)陣列,不過(guò)要注意的是你將會(huì)回傳一個(gè)屬于 error 資料型態(tài)的錯(cuò)誤,所以你需要引用 errors 套件來(lái)幫助你做這件事。

該注意的是Golang沒有 try .. catch ,因?yàn)?Golang推薦這種錯(cuò)誤處理方式 ,你應(yīng)該在每一次執(zhí)行可能會(huì)發(fā)生錯(cuò)誤的程式時(shí)就處理錯(cuò)誤,而非后來(lái)用 try 到處包覆你的程式。

在 if 條件式里宣告變數(shù)會(huì)讓你只能在 if 內(nèi)部使用這個(gè)變數(shù),而不會(huì)污染到全域范圍。

也許你在PHP中更常用的會(huì)是 try .. catch ,在大型商業(yè)邏輯時(shí)經(jīng)??匆娙绱说赜梅ǎ瑢?shí)際上這種用法令人感到聒噪(因?yàn)槟銜?huì)需要一堆 try 區(qū)塊):

Golang中并沒有 try .. catch ,實(shí)際上Golang也 不鼓勵(lì)這種行為 (Golang推薦逐一處理錯(cuò)誤的方式),倘若你真想辦倒像是捕捉異常這樣的方式,你確實(shí)可以使用Golang中另類處理錯(cuò)誤的方式(可以的話盡量避免使用這種方式): panic() , recover() , defer 。

你可以把 panic() 當(dāng)作是 throw (丟出錯(cuò)誤),而這跟PHP的 exit() 有87%像,一但你執(zhí)行了 panic() 你的程式就會(huì)宣告而終,但是別擔(dān)心,因?yàn)槌淌浇Y(jié)束的時(shí)候會(huì)呼叫 defer ,所以我們接下來(lái)要在 defer 停止 panic() 。

關(guān)于 defer 上述已經(jīng)有提到了,他是一個(gè)反向執(zhí)行的宣告,會(huì)在函式結(jié)束后被執(zhí)行,當(dāng)你呼叫了 panic() 結(jié)束程式的時(shí)候,也就會(huì)開始執(zhí)行 defer ,所以我們要在 defer 內(nèi)使用 recover() 讓程式不再繼續(xù)進(jìn)行結(jié)束動(dòng)作,這就像是捕捉異常。

recover() 可以看作 catch (捕捉),我們要在 defer 里面用 recover() 解決 panic() ,如此一來(lái)程式就會(huì)回歸正常而不會(huì)被結(jié)束。

還記得在PHP里要引用一堆檔案的日子嗎?到處可見的 require() 或是 include() ?到了Golang這些都不見了,取而代之的是「套件(Package)」?,F(xiàn)在讓我們來(lái)用PHP解釋一下。

這看起來(lái)很正常對(duì)吧?但假設(shè)你有一堆檔案,這馬上就成了 Include Hell ,讓我們看看Golang怎么透過(guò)「套件」解決這個(gè)問題。

「 蛤???殺小??? 」你可能如此地說(shuō)道。是的, main.go 中除了引用 fmt 套件( 為了要輸出結(jié)果用的套件 )之外完全沒有引用到 a.go 。

「 蛤???殺?。?????? 」你仿佛回到了幾秒鐘前的自己。

既然沒有引用其他檔案,為什么 main.go 可以輸出 foo 呢?注意到了嗎, 兩者都是屬于 main 套件 ,因此 他們共享同一個(gè)區(qū)域 ,所以接下來(lái)要介紹的是什么叫做「套件」。

套件是每一個(gè) .go 檔案都必須聲明在Golang原始碼中最開端的東西,像下面這樣:

這意味著目前的檔案是屬于 main 套件( 你也可以依照你的喜好命名 ),那么要如何讓同個(gè)套件之間的函式溝通呢?

接著是Golang;注意!你不需要引用任何檔案,因?yàn)橄铝袃蓚€(gè)檔案同屬一個(gè)套件。

一個(gè)由「套件」所掌握的世界,比起PHP的 include() 和 require() 還要好太多了,對(duì)嗎?

在Golang 中沒有引用單獨(dú)檔案的方式,你必須匯入一整個(gè)套件,而且你要記?。骸敢欢銋R入了,你就一定要使用它」,像下面這樣。

假如你不希望使用你匯入的套件,你只是為了要觸發(fā)那個(gè)套件的 main() 函式而引用的話??,那么你可以在前面加上一個(gè)底線( _ )。

如果你的套件出現(xiàn)了名稱沖突,你可以在套件來(lái)源前面給他一個(gè)新的名稱。

現(xiàn)在你知道可以匯入套件了,那么什么是「匯出」?同個(gè)套件內(nèi)的函式還有共享變數(shù)確實(shí)可以直接用,但那 并不表示可以給其他套件使用 ,其方法取決于 函式/變數(shù)的「開頭大小寫」 。

是的。 Golang依照一個(gè)函式/變數(shù)的開頭大小寫決定這個(gè)東西是否可供「匯出」 。

這用在區(qū)別函式的時(shí)候格外有用,因?yàn)樾戦_頭的任何事物都是不供匯出的,反之,大寫開頭的任何事物都是用來(lái)匯出供其他套件使用的。

一開始可能會(huì)覺得這是什么奇異的規(guī)定,但寫久之后,你就能發(fā)現(xiàn)比起JavaScript和Python以「底線為開頭的命名方式」還要來(lái)得更好;比起成天宣告 public 、 private 、 protected 還要來(lái)得更快。

在Golang 中沒有類別,但有所謂的「建構(gòu)體(Struct)」和「接口(Interface)」,這就能夠滿足幾乎所有的需求了,這也是為什么我認(rèn)為Golang 很簡(jiǎn)潔卻又很強(qiáng)大的原因。

讓我們先用PHP 建立一個(gè)類別,然后看看Golang 怎么解決這個(gè)問題。

雖然Golang沒有類別,但是「建構(gòu)體(Struct)」就十分地堪用了,首先你要知道在Golang中「類別」的成員還有方法都是在「類別」外面所定義的,這跟PHP在類別內(nèi)定義的方式有所不同,在Golang中還有一點(diǎn),那就是他們沒有 public 、 private 、 protected 的種類。

在PHP中,當(dāng)有一個(gè)類別被 new 的時(shí)候會(huì)自動(dòng)執(zhí)行該類別內(nèi)的建構(gòu)子( __construct() ),通常你會(huì)用這個(gè)來(lái)初始化一些類別內(nèi)部的值。

但是在Golang 里因?yàn)闆]有類別,也就沒有建構(gòu)子,不巧的是建構(gòu)體本身也不帶有建構(gòu)子的特性,這個(gè)時(shí)候你只能自己在外部建立一個(gè)建構(gòu)用函式。

讓我們假設(shè)你有兩個(gè)類別,你會(huì)把其中一個(gè)類別傳入到另一個(gè)類別里面使用,廢話不多說(shuō)!先上個(gè)PHP 范例(為了簡(jiǎn)短篇幅我省去了換行)。

在Golang中你也有相同的用法,但是請(qǐng)記得:「 任何東西都是在「類別」外完成建構(gòu)的 」。

在PHP 中沒有相關(guān)的范例,這部分會(huì)以剛才「嵌入」章節(jié)中的Golang 范例作為解說(shuō)對(duì)象。

你可以看見Golang在進(jìn)行 Foo 嵌入 Bar 的時(shí)候,會(huì)自動(dòng)將 Foo 的成員暴露在 Bar 底下,那么假設(shè)「雙方之間有相同的成員名稱」呢?

這個(gè)時(shí)候被嵌入的成員就會(huì)被「遮蔽」,下面是個(gè)實(shí)際范例,還有你如何解決遮蔽問題:

雖然都是呼叫同一個(gè)函式,但是這個(gè)函式可以針對(duì)不同的資料來(lái)源做出不同的舉動(dòng),這就是多形。你也能夠把這看作是:「訊息的意義由接收者定義,而不是傳送者」。

目前PHP 中沒有真正的「多形」,不過(guò)你仍可以做出同樣的東西。

嗯??那么Golang呢?實(shí)際上更簡(jiǎn)單而且更有條理了,在Golang中有 interface 可以幫忙完成這個(gè)工作。

如果你對(duì)Interface還不熟悉,可以試著查看「 解釋Golang中的Interface到底是什么 」文章。

謝謝你看到這里,可惜這篇文章卻沒有說(shuō)出Golang 最重要的賣點(diǎn):「Goroutine」和「Channel」

golang json:怎么替代yaml:

安裝EasyDataTransform在Mac上就可以解決。

安裝EasyDataTransform在Mac上,開始輕松的數(shù)據(jù)轉(zhuǎn)換,將要顯示重復(fù)項(xiàng)的Excel電子表格拖到EasyDataTransform上。將添加一個(gè)粉紅色的輸入項(xiàng)請(qǐng)注意右側(cè)窗格中的JSON數(shù)據(jù)已自動(dòng)“展平”到表格中。

您可以將右窗格中的Format下拉菜單設(shè)置為L(zhǎng)ong或Wide,具體取決于您希望表格具有更多行還是更多列,確保選擇了粉紅色的輸入項(xiàng),單擊左窗格中的ToFile按鈕,將出現(xiàn)一個(gè)窗口。設(shè)置新文件名和位置。選擇YAML文件作為文件類型。添加并選擇了一個(gè)綠色輸出項(xiàng)。YAML文件會(huì)立即創(chuàng)建,無(wú)需“運(yùn)行”任何內(nèi)容您可以在右側(cè)窗格中更改YAML文件編碼。

Go中標(biāo)簽的用途是什么?

字段標(biāo)簽允許您將元信息附加到可以使用反射獲取的字段上。通常,它用于提供有關(guān)如何將結(jié)構(gòu)域編碼為另一種格式(或從另一種格式存儲(chǔ)(或從數(shù)據(jù)庫(kù)中檢索))的轉(zhuǎn)換信息,但是您可以使用它存儲(chǔ)想要存儲(chǔ)的任何元信息,這些元信息既可以用于另一種包裝或供您自己使用。

如的文檔所述reflect.StructTag,按照慣例,標(biāo)記字符串的值是用空格分隔的key:"value"成對(duì)列表,如:

type User struct {

Name string `json:"name" xml:"name"`

}

的key通常表示包,隨后的"value"是,如json密鑰被處理/使用的encoding/json包。

如果要在中傳遞多個(gè)信息"value",通常通過(guò)用逗號(hào)(',')隔開來(lái)指定它,如

Name string `json:"name,omitempty" xml:"name"`

通常用破折號(hào)('-')"value"表示將字段從過(guò)程中排除(如,在這種情況下,json表示不封送或取消封送該字段)。

使用反射訪問自定義標(biāo)簽的示例

我們可以使用反射(reflect包)來(lái)訪問結(jié)構(gòu)字段的標(biāo)記值?;旧?,我們需要獲取Type結(jié)構(gòu)的,然后可以使用Type.Field(i

int)或查詢字段Type.FieldByName(name

string)。這些方法返回的值StructField描述/表示一個(gè)struct字段;并且StructField.Tag是StructTag描述/表示標(biāo)記值的類型值。

以前我們談?wù)撨^(guò) “慣例” 。該公約的手段,如果你遵循它,你可以使用StructTag.Get(key

string)它解析變量的值,并返回該方法"value"的key指定。該公約實(shí)施/內(nèi)置到這個(gè)Get()方法。如果不遵守約定,Get()將無(wú)法解析key:"value"對(duì)并找到您要查找的內(nèi)容。這也不是問題,但是隨后您需要實(shí)現(xiàn)自己的解析邏輯。

還有StructTag.Lookup()(在Go1.7中添加了),它 “類似于,Get()但是將不包含給定鍵的標(biāo)簽與將空字符串與給定鍵相關(guān)聯(lián)的標(biāo)簽區(qū)分開”。因此,看一個(gè)簡(jiǎn)單的示例:

type User struct {

Name ?string `mytag:"MyName"`

Email string `mytag:"MyEmail"`}

u := User{"Bob", "bob@mycompany.com"}

t := reflect.TypeOf(u)for _, fieldName := range []string{"Name", "Email"} {

field, found := t.FieldByName(fieldName) ? ?if !found { ? ? ? ?continue

}

fmt.Printf("\nField: User.%s\n", fieldName)

fmt.Printf("\tWhole tag value : %q\n", field.Tag)

fmt.Printf("\tValue of 'mytag': %q\n", field.Tag.Get("mytag"))

}

輸出(在Go Playground上嘗試):

Field: User.Name

Whole tag value : "mytag:\"MyName\""

Value of 'mytag': "MyName"Field: User.Email

Whole tag value : "mytag:\"MyEmail\""

Value of 'mytag': "MyEmail"

GopherCon 2015上有一個(gè)關(guān)于struct標(biāo)簽的演示,名為:結(jié)構(gòu)標(biāo)簽的許多面孔(幻燈片)

(和視頻)以下是常用標(biāo)簽鍵的列表:

json-由encoding/json包裝使用,詳細(xì)說(shuō)明json.Marshal()

xml-由encoding/xml包裝使用,詳細(xì)說(shuō)明xml.Marshal()

bson-由gobson使用,詳細(xì)說(shuō)明bson.Marshal()

protobuf-由github.com/golang/protobuf/proto,在軟件包doc中有詳細(xì)說(shuō)明

yaml-由gopkg.in/yaml.v2包裝使用,詳細(xì)說(shuō)明yaml.Marshal()

db-由github.com/jmoiron/sqlx包裝使用;也被github.com/go-gorp/gorp包裝使用

orm-由github.com/astaxie/beego/orm包裝使用,在“ 型號(hào)– Beego ORM”中有詳細(xì)說(shuō)明

gorm-由github.com/jinzhu/gorm軟件包使用,示例可在其文檔中找到:模型

valid-由github.com/asaskevich/govalidator軟件包使用,示例可以在項(xiàng)目頁(yè)面中找到

datastore-由appengine/datastore(Google App Engine平臺(tái),數(shù)據(jù)存儲(chǔ)區(qū)服務(wù))使用,在“ 屬性”中有詳細(xì)說(shuō)明

schema-用于通過(guò)HTML表單值github.com/gorilla/schema填充(struct包文檔中有詳細(xì)說(shuō)明)

asn-由encoding/asn1包裝使用,詳細(xì)說(shuō)明在asn1.Marshal()和asn1.Unmarshal()

csv-由github.com/gocarina/gocsv包裝使用

名稱欄目:go語(yǔ)言解析yaml go語(yǔ)言解析注釋
網(wǎng)頁(yè)地址:http://jinyejixie.com/article22/hpdijc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)定制網(wǎng)站、網(wǎng)站營(yíng)銷網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
平罗县| 洛阳市| 葫芦岛市| 望奎县| 镇赉县| 石河子市| 无为县| 黄浦区| 社会| 吉林市| 稷山县| 日土县| 同德县| 桃源县| 耿马| 湘潭市| 福安市| 牟定县| 津市市| 丰原市| 昆山市| 嘉禾县| 姚安县| 深泽县| 明光市| 那坡县| 西充县| 宜兰市| 望都县| 嵊州市| 阜新市| 芜湖市| 沈阳市| 禹城市| 龙门县| 中山市| 桃江县| 濉溪县| 白山市| 万全县| 汶川县|