本文目錄一覽:
- 1、基礎知識 – Golang 中的格式化輸入輸出
- 2、golang在將struct轉成json字元串的時候如何將日期類型的數據格式化?
- 3、golang logger輸出格式怎麼修改
- 4、怎麼學習golang
- 5、Go語言基礎語法(一)
- 6、golangci-line 工具介紹
基礎知識 – Golang 中的格式化輸入輸出
【格式化輸出】
// 格式化輸出:將 arg 列表中的 arg 轉換為字元串輸出
// 使用動詞 v 格式化 arg 列表,非字元串元素之間添加空格
Print(arg列表)
// 使用動詞 v 格式化 arg 列表,所有元素之間添加空格,結尾添加換行符
Println(arg列表)
// 使用格式字元串格式化 arg 列表
Printf(格式字元串, arg列表)
// Print 類函數會返回已處理的 arg 數量和遇到的錯誤信息。
【格式字元串】
格式字元串由普通字元和佔位符組成,例如:
“abc%+ #8.3[3]vdef”
其中 abc 和 def 是普通字元,其它部分是佔位符,佔位符以 % 開頭(註:%% 將被轉義為一個普通的 % 符號,這個不算開頭),以動詞結尾,格式如下:
%[旗標][寬度][.精度][arg索引]動詞
方括弧中的內容可以省略。
【旗標】
旗標有以下幾種:
空格:對於數值類型的正數,保留一個空白的符號位(其它用法在動詞部分說明)。
0 :用 0 進行寬度填充而不用空格,對於數值類型,符號將被移到所有 0 的前面。
其中 “0” 和 “-” 不能同時使用,優先使用 “-” 而忽略 “0”。
【寬度和精度】
「寬度」和「精度」都可以寫成以下三種形式:
數值 | * | arg索引*
其中「數值」表示使用指定的數值作為寬度值或精度值,「 」表示使用當前正在處理的 arg 的值作為寬度值或精度值,如果這樣的話,要格式化的 arg 將自動跳轉到下一個。「arg索引 」表示使用指定 arg 的值作為寬度值或精度值,如果這樣的話,要格式化的 arg 將自動跳轉到指定 arg 的下一個。
寬度值:用於設置最小寬度。
精度值:對於浮點型,用於控制小數位數,對於字元串或位元組數組,用於控制字元數量(不是位元組數量)。
對於浮點型而言,動詞 g/G 的精度值比較特殊,在適當的情況下,g/G 會設置總有效數字,而不是小數位數。
【arg 索引】
「arg索引」由中括弧和 arg 序號組成(就像上面示例中的 [3]),用於指定當前要處理的 arg 的序號,序號從 1 開始:
‘[‘ + arg序號 + ‘]’
【動詞】
「動詞」不能省略,不同的數據類型支持的動詞不一樣。
[通用動詞]
v:默認格式,不同類型的默認格式如下:
布爾型:t
整 型:d
浮點型:g
複數型:g
字元串:s
通 道:p
指 針:p
無符號整型:x
T:輸出 arg 的類型而不是值(使用 Go 語法格式)。
[布爾型]
t:輸出 true 或 false 字元串。
[整型]
b/o/d:輸出 2/8/10 進位格式
x/X :輸出 16 進位格式(小寫/大寫)
c :輸出數值所表示的 Unicode 字元
q :輸出數值所表示的 Unicode 字元(帶單引號)。對於無法顯示的字元,將輸出其轉義字元。
U :輸出 Unicode 碼點(例如 U+1234,等同於字元串 “U+%04X” 的顯示結果)
對於 o/x/X:
如果使用 “#” 旗標,則會添加前導 0 或 0x。
對於 U:
如果使用 “#” 旗標,則會在 Unicode 碼點後面添加相應的 ‘字元’(前提是該字元必須可顯示)
[浮點型和複數型]
b :科學計數法(以 2 為底)
e/E:科學計數法(以 10 為底,小寫 e/大寫 E)
f/F:普通小數格式(兩者無區別)
g/G:大指數(指數 = 6)使用 %e/%E,其它情況使用 %f/%F
[字元串或位元組切片]
s :普通字元串
q :雙引號引起來的 Go 語法字元串
x/X:十六進位編碼(小寫/大寫,以位元組為元素進行編碼,而不是字元)
對於 q:
如果使用了 “+” 旗標,則將所有非 ASCII 字元都進行轉義處理。
如果使用了 “#” 旗標,則輸出反引號引起來的字元串(前提是
字元串中不包含任何製表符以外的控制字元,否則忽略 # 旗標)
對於 x/X:
如果使用了 ” ” 旗標,則在每個元素之間添加空格。
如果使用了 “#” 旗標,則在十六進位格式之前添加 0x 前綴。
[指針類型]
p :帶 0x 前綴的十六進位地址值。
[符合類型]
複合類型將使用不同的格式輸出,格式如下:
結 構 體:{欄位1 欄位2 …}
數組或切片:[元素0 元素1 …]
映 射:map[鍵1:值1 鍵2:值2 …]
指向符合元素的指針:{}, [], map[]
複合類型本身沒有動詞,動詞將應用到複合類型的元素上。
結構體可以使用 “+v” 同時輸出欄位名。
【注意】
1、如果 arg 是一個反射值,則該 arg 將被它所持有的具體值所取代。
2、如果 arg 實現了 Formatter 介面,將調用它的 Format 方法完成格式化。
3、如果 v 動詞使用了 # 旗標(%#v),並且 arg 實現了 GoStringer 介面,將調用它的 GoString 方法完成格式化。
如果格式化操作指定了字元串相關的動詞(比如 %s、%q、%v、%x、%X),接下來的兩條規則將適用:
4。如果 arg 實現了 error 介面,將調用它的 Error 方法完成格式化。
5。如果 arg 實現了 string 介面,將調用它的 String 方法完成格式化。
在實現格式化相關介面的時候,要避免無限遞歸的情況,比如:
type X string
func (x X) String() string {
return Sprintf(“%s”, x)
}
在格式化之前,要先轉換數據類型,這樣就可以避免無限遞歸:
func (x X) String() string {
return Sprintf(“%s”, string(x))
}
無限遞歸也可能發生在自引用數據類型上面,比如一個切片的元素引用了切片自身。這種情況比較罕見,比如:
a := make([]interface{}, 1)
a[0] = a
fmt.Println(a)
【格式化輸入】
// 格式化輸入:從輸入端讀取字元串(以空白分隔的值的序列),
// 並解析為具體的值存入相應的 arg 中,arg 必須是變數地址。
// 字元串中的連續空白視為單個空白,換行符根據不同情況處理。
// \r\n 被當做 \n 處理。
// 以動詞 v 解析字元串,換行視為空白
Scan(arg列表)
// 以動詞 v 解析字元串,換行結束解析
Scanln(arg列表)
// 根據格式字元串中指定的格式解析字元串
// 格式字元串中的換行符必須和輸入端的換行符相匹配。
Scanf(格式字元串, arg列表)
// Scan 類函數會返回已處理的 arg 數量和遇到的錯誤信息。
【格式字元串】
格式字元串類似於 Printf 中的格式字元串,但下面的動詞和旗標例外:
p :無效
T :無效
e/E/f/F/g/G:功能相同,都是掃描浮點數或複數
s/v :對字元串而言,掃描一個被空白分隔的子串
對於整型 arg 而言,v 動詞可以掃描帶有前導 0 或 0x 的八進位或十六進位數值。
寬度被用來指定最大掃描寬度(不會跨越空格),精度不被支持。
如果 arg 實現了 Scanner 介面,將調用它的 Scan 方法掃描相應數據。只有基礎類型和實現了 Scanner 介面的類型可以使用 Scan 類方法進行掃描。
【注意】
連續調用 FScan 可能會丟失數據,因為 FScan 中使用了 UnreadRune 對讀取的數據進行撤銷,而參數 io.Reader 只有 Read 方法,不支持撤銷。比如:
golang在將struct轉成json字元串的時候如何將日期類型的數據格式化?
如果你想輸出的時間是YYYY-MM-DD的話
要在使用json數據化之前自己處理時間
type Article struct {
Id int
Title string
CreateTimeStr string
}
然後要將之前的時間轉過來
Article.CreateTimeStr = Createdatetime.Format(“2006-01-02”)
最後序列化JSON就是YYYY-MM-DD
這是最簡單的方法
golang logger輸出格式怎麼修改
1.Logger結構
首先來看下類型Logger的定義:
type Logger struct {
mu sync.Mutex // ensures atomic writes; protects the following fields
prefix string // prefix to write at beginning of each line
flag int // properties
out io.Writer // destination for output
buf []byte // for accumulating text to write
}
主要有5個成員,其中3個我們比較熟悉,分別是表示Log前綴的 “prefix”,表示Log頭標籤的 “flag” ,以及Log的輸出目的地out。 buf是一個位元組數組,主要用來存放即將刷入out的內容,相當於一個臨時緩存,在對輸出內容進行序列化時作為存儲目的地。 mu是一個mutex主要用來作線程安全的實習,當有多個goroutine同時往一個目的刷內容的時候,通過mutex保證每次寫入是一條完整的信息。
2.std及整體結構
在前一篇文章中我們提到了log模塊提供了一套包級別的簡單介面,使用該介面可以直接將日誌內容列印到標準錯誤。那麼該過程是怎麼實現的呢?其實就是通過一個內置的Logger類型的變數 “std” 來實現的。該變數使用:
var std = New(os.Stderr, “”, LstdFlags)
進行初始化,默認輸出到系統的標準輸出 “os.Stderr” ,前綴為空,使用日期加時間作為Log抬頭。
當我們調用 log.Print的時候是怎麼執行的呢?我們看其代碼:
func Print(v …interface{}) {
std.Output(2, fmt.Sprint(v…))
}
這裡實際就是調用了Logger對象的 Output方法,將日誌內容按照fmt包中約定的格式轉義後傳給Output。Output定義如下 :
func (l *Logger) Output(calldepth int, s string) error
其中s為日誌沒有加前綴和Log抬頭的具體內容,xxxxx 。該函數執行具體的將日誌刷入到對應的位置。
3.核心函數的實現
Logger.Output是執行具體的將日誌刷入到對應位置的方法。
該方法首先根據需要獲得當前時間和調用該方法的文件及行號信息。然後調用formatHeader方法將Log的前綴和Log抬頭先格式化好 放入Logger.buf中,然後再將Log的內容存入到Logger.buf中,最後調用Logger.out.Write方法將完整的日誌寫入到輸出目的地中。
由於寫入文件以及拼接buf的過程是線程非安全的,因此使用mutex保證每次寫入的原子性。
l.mu.Lock()
defer l.mu.Unlock()
將buf的拼接和文件的寫入放入這個後面,使得在多個goroutine使用同一個Logger對象是,不會弄亂buf,也不會雜糅的寫入。
該方法的第一個參數最終會傳遞給runtime.Caller的skip,指的是跳過的棧的深度。這裡我記住給2就可以了。這樣就會得到我們調用log 是所處的位置。
在golang的注釋中說鎖住 runtime.Caller的過程比較重,這點我還是不很了解,只是從代碼中看到其在這裡把鎖打開了。
if l.flag(Lshortfile|Llongfile) != 0 {
// release lock while getting caller info – it『s expensive.
l.mu.Unlock()
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = “???”
line = 0
}
l.mu.Lock()
}
在formatHeader裡面首先將前綴直接複製到Logger.buf中,然後根據flag選擇Log抬頭的內容,這裡用到了一個log模塊實現的 itoa的方法,作用類似c的itoa,將一個整數轉換成一個字元串。只是其轉換後將結果直接追加到了buf的尾部。
縱觀整個實現,最值得學習的就是線程安全的部分。在什麼位置合適做怎樣的同步操作。
4.對外介面的實現
在了解了核心格式化和輸出結構後,在看其封裝就非常簡單了,幾乎都是首先用Output進行日誌的記錄,然後在必要的時候 做os.exit或者panic的操作,這裡看下Fatal的實現。
func (l *Logger) Fatal(v …interface{}) {
l.Output(2, fmt.Sprint(v…))
os.Exit(1)
}
// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, v …interface{}) {
l.Output(2, fmt.Sprintf(format, v…))
os.Exit(1)
}
// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
func (l *Logger) Fatalln(v …interface{}) {
l.Output(2, fmt.Sprintln(v…))
os.Exit(1)
}
這裡也驗證了我們之前做的Panic的結果,先做輸出日誌操作。再進行panic。
怎麼學習golang
已經有好多程序員都把Go語言描述為是一種所見即所得(WYSIWYG)的編程語言。這是說,代碼要做的事和它在字面上表達的意思是完全一致的。 在這些新語言中,包含D,Go,Rust和Vala語言,Go曾一度出現在TIOBE的排行榜上面。與其他新語言相比,Go的魅力明顯要大很多。Go的成熟特徵會得到許多開發者的欣賞,而不僅僅是因為其誇大其詞的曝光度。下面我們來一起探討一下谷歌開發的Go語言以及談談Go為什麼會吸引眾多開發者: 快速簡單的編譯 Go編譯速度很快,如此快速的編譯使它很容易作為腳本語言使用。關於編譯速度快主要有以下幾個原因:首先,Go不使用頭文件;其次如果一個模塊是依賴A的,這反過來又取決於B,在A裡面的需求改變只需重新編譯原始模塊和與A相依賴的地方;最後,對象模塊裡面包含了足夠的依賴關係信息,所以編譯器不需要重新創建文件。你只需要簡單地編譯主模塊,項目中需要的其他部分就會自動編譯,很酷,是不是? 通過返回數值列表來處理錯誤信息 目前,在本地語言裡面處理錯誤的方式主要有兩種:直接返回代碼或者拋異常。這兩種都不是最理想的處理方式。其中返回代碼是非常令人沮喪的,因為返回的錯誤代碼經常與從函數中返回的數據相衝突。Go允許函數返回多個值來解決這個問題。這個從函數裡面返回的值,可以用來檢查定義的類型是否正確並且可以隨時隨地對函數的返回值進行檢查。如果你對錯誤值不關心,你可以不必檢查。在這兩種情況下,常規的返回值都是可用的。 簡化的成分(優先於繼承) 通過使用介面,類型是有資格成為對象中一員的,就像Java指定行為一樣。例如在標準庫裡面的IO包,定義一個Writer來指定一個方法,一個Writer函數,其中輸入參數是位元組數組並且返回整數類型值或者錯誤類型。任何類型實現一個帶有相同簽名的Writer方法是對IO的完全實現,Writer介面。這種是解耦代碼而不是優雅。它還簡化了模擬對象來進行單元測試。例如你想在資料庫對象中測試一個方法,在標準語言中,你通常需要創建一個資料庫對象,並且需要進行大量的初始化和協議來模擬對象。在Go裡面,如果該方法需要實現一個介面,你可以創建任何對該介面有用的對象,所以,你創建了MockDatabase,這是很小的對象,只實現了幾個需要運行和模擬的介面——沒有構造函數,沒有附件功能,只是一些方法。 簡化的並發性 相對於其他語言,並發性在Go裡面顯得更加容易。把『go』關鍵字放在任意函數前面然後那個函數就會在其go-routine自動運行(一個很輕的線程)。go-routines是通過通道進行交流並且基本上封鎖了所有的隊列消息。普通工具對相互排斥是有用,但是Go通過使用通道來踢掉並發性任務和坐標更加容易。 優秀的錯誤消息 所有與Go相似的語言,自身作出的診斷都是無法與Go相媲美的。例如,一個死鎖程序,在Go運行時會通知你目前哪個線程導致了這種死鎖。編譯的錯誤信息是非常詳細全面和有用的。 其他 這裡還有許多其他吸引人的地方,下面就一概而過的介紹一下,比如高階函數、垃圾回收、哈希映射和可擴展的數組內置語言(部分語言語法,而不是作為一個庫)等等。 當然,Go並不是完美無瑕。在工具方面還有些不成熟的地方和用戶社區較小等,但是隨著谷歌語言的不斷發展,肯定會有整治措施出來。儘管許多語言,尤其是D、Rust和Vala旨在簡化C++並且對其進行簡化,但它們給人的感覺仍是「C++看上去要更好」。
【Go語言的優勢】
可直接編譯成機器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去就完成了。
靜態類型語言,但是有動態語言的感覺,靜態類型的語言就是可以在編譯的時候檢查出來隱藏的大多數問題,動態語言的感覺就是有很多的包可以使用,寫起來的效率很高。
語言層面支持並發,這個就是Go最大的特色,天生的支持並發,我曾經說過一句話,天生的基因和整容是有區別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因裡面支持的並發,可以充分的利用多核,很容易的使用並發。
內置runtime,支持垃圾回收,這屬於動態語言的特性之一吧,雖然目前來說GC不算完美,但是足以應付我們所能遇到的大多數情況,特別是Go1.1之後的GC。
簡單易學,Go語言的作者都有C的基因,那麼Go自然而然就有了C的基因,那麼Go關鍵字是25個,但是表達能力很強大,幾乎支持大多數你在其他語言見過的特性:繼承、重載、對象等。
豐富的標準庫,Go目前已經內置了大量的庫,特別是網路庫非常強大,我最愛的也是這部分。
內置強大的工具,Go語言裡面內置了很多工具鏈,最好的應該是gofmt工具,自動化格式化代碼,能夠讓團隊review變得如此的簡單,代碼格式一模一樣,想不一樣都很困難。
跨編譯,如果你寫的Go代碼不包含cgo,那麼就可以做到window系統編譯linux的應用,如何做到的呢?Go引用了plan9的代碼,這就是不依賴系統的信息。
內嵌C支持,前面說了作者是C的作者,所以Go裡面也可以直接包含c代碼,利用現有的豐富的C庫。
Go語言基礎語法(一)
本文介紹一些Go語言的基礎語法。
先來看一個簡單的go語言代碼:
go語言的注釋方法:
代碼執行結果:
下面來進一步介紹go的基礎語法。
go語言中格式化輸出可以使用 fmt 和 log 這兩個標準庫,
常用方法:
示例代碼:
執行結果:
更多格式化方法可以訪問中的fmt包。
log包實現了簡單的日誌服務,也提供了一些格式化輸出的方法。
執行結果:
下面來介紹一下go的數據類型
下表列出了go語言的數據類型:
int、float、bool、string、數組和struct屬於值類型,這些類型的變數直接指向存在內存中的值;slice、map、chan、pointer等是引用類型,存儲的是一個地址,這個地址存儲最終的值。
常量是在程序編譯時就確定下來的值,程序運行時無法改變。
執行結果:
執行結果:
Go 語言的運算符主要包括算術運算符、關係運算符、邏輯運算符、位運算符、賦值運算符以及指針相關運算符。
算術運算符:
關係運算符:
邏輯運算符:
位運算符:
賦值運算符:
指針相關運算符:
下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯用,這裡不做介紹。
if語法格式如下:
if … else :
else if:
示例代碼:
語法格式:
另外,添加 fallthrough 會強制執行後面的 case 語句,不管下一條case語句是否為true。
示例代碼:
執行結果:
下面介紹幾種循環語句:
執行結果:
執行結果:
也可以通過標記退出循環:
–THE END–
golangci-line 工具介紹
在 ci 過程中,經常有一些可以通過靜態分析或者白盒檢測去避免一些問題以及規範代碼格式!使用Go語言一般是使用 golangci-line 作為代碼檢測工具!
參考官網:
安裝: curl-sSfL | sh -s — -b $(go env GOPATH)/bin v1.43.0
版本信息: golangci-lint–version
目前我司是自己二開的 golangci-line,所以這裡使用的開源版本,其實大同小異,就是開發了一些插件!
這個就是一個工具,集成了各類自動檢測代碼的工具,所以不需要本地安裝太多的工具,只需要這個工具即可!
由於它需要一個go的項目,這裡以我自己的項目去介紹, 項目地址:,如果有同學想自己嘗試下可以直接下載我這個項目!項目也比較規範!
其實執行 golangci-lint run-h 就可以獲取以下幫助
例如我經常使用的: 我日常就是開啟format功能!
1、默認使用的插件
2、默認沒用的
3、presets 分類:
具體可以參考我的:
主要是做一些 無用代碼檢測,簡化代碼,格式化代碼!然後執行 golangci-lint run –fix 即可
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/190611.html