go語言占位符作用_ go 占位符

Go語言的%d,%p,%v等占位符的使用

這些是死知識,把常用的記住,不常用的直接查表就行了

站在用戶的角度思考問題,與客戶深入溝通,找到荔浦網(wǎng)站設(shè)計與荔浦網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、申請域名、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋荔浦地區(qū)。

golang 的fmt 包實現(xiàn)了格式化I/O函數(shù),類似于C的 printf 和 scanf。

type Human struct {

Name string

}

var people = Human{Name:"zhangsan"}

golang沒有 '%u' 點位符,若整數(shù)為無符號類型,默認就會被打印成無符號的。

寬度與精度的控制格式以Unicode碼點為單位。寬度為該數(shù)值占用區(qū)域的最小寬度;精度為小數(shù)點之后的位數(shù)。

操作數(shù)的類型為int時,寬度與精度都可用字符 '*' 表示。

對于 %g/%G 而言,精度為所有數(shù)字的總數(shù),例如:123.45,%.4g 會打印123.5,(而 %6.2f 會打印123.45)。

%e 和 %f 的默認精度為6

對大多數(shù)的數(shù)值類型而言,寬度為輸出的最小字符數(shù),如果必要的話會為已格式化的形式填充空格。

而以字符串類型,精度為輸出的最大字符數(shù),如果必要的話會直接截斷。

使用起來很簡單,一般配合fmt.Printf()使用,因為fmt的Printf()是有格式的輸出,切忌使用Println(),否則將會以字符串的形式輸出。

查看原文: golang fmt格式“占位符”

Go 空結(jié)構(gòu)體 struct{} 的使用

struct是Go中的關(guān)鍵字,用于定義結(jié)構(gòu)類型。

例如:

struct {}是一個無元素的結(jié)構(gòu)體類型,通常在沒有信息存儲時使用。優(yōu)點是大小為0,不需要內(nèi)存來存儲struct {}類型的值。

struct {} {}是一個復(fù)合字面量,它構(gòu)造了一個struct {}類型的值,該值也是空。

go中可以使用 unsafe.Sizeof 計算出一個數(shù)據(jù)類型實例需要占用的字節(jié)數(shù)。我們驗證一下:

也就是說空結(jié)構(gòu)體實例不占用任何內(nèi)存空間。

Go 語言標(biāo)準(zhǔn)庫沒有提供 Set 的實現(xiàn),通常使用 map 來代替。事實上,對于集合來說,只需要 map 的鍵,而不需要值。

聲明為聲明為 map[string]struct{} ,由于struct{}是空,不關(guān)心內(nèi)容,這樣map便改造為set 。

map可以通過“comma ok”機制來獲取該key是否存在,例如 _, ok := map["key"] ,如果沒有對應(yīng)的值,ok為false??梢酝ㄟ^定義成 map[string]struct{} 的形式,值不再占用內(nèi)存。其值僅有兩種狀態(tài),有或無。如果定義的是 map[string]bool ,則結(jié)果有true、false或沒有三種狀態(tài),而且即使是將值設(shè)置為 bool 類型,也會多占據(jù) 1 個字節(jié)。因此呢,將 map 作為集合(Set)使用時,可以將值類型定義為空結(jié)構(gòu)體,僅作為占位符使用即可。

基于channels發(fā)送消息有兩個重要方面:發(fā)了消息、發(fā)了什么消息。一個強調(diào)了通訊的發(fā)生,一個強調(diào)了通訊的內(nèi)容。當(dāng)我們更希望強調(diào)通訊發(fā)生的時刻時,我們將它稱為 消息事件 。有些消息事件并不攜帶額外的信息,它僅僅是用作兩個goroutine之間的同步,這時候我們可以用 struct{} 空結(jié)構(gòu)體作為channels元素的類型。用來通知子協(xié)程(goroutine)執(zhí)行任務(wù),或只用來控制協(xié)程并發(fā)度。

在部分場景下,結(jié)構(gòu)體只包含方法,不包含任何的字段。這時候我們就可以使用空結(jié)構(gòu)體。

其實,上面的calculateInt 可以是任何類型,如 type calculateInt bool ,但是struct{}不占用任何空間,邏輯上也更合理,因此還是它最好。

Go 中這么多創(chuàng)建 error 的方式,你真的了解它們各自的應(yīng)用場景嗎

在Go中,error是一種內(nèi)建的數(shù)據(jù)類型。在Go中被定義為一個接口,定義如下:

由此可知,該接口只有一個返回字符串的Error函數(shù),所有的類型只要實現(xiàn)了該函數(shù),就創(chuàng)建了一個錯誤類型。

創(chuàng)建error的方式包括errors.New、fmt.Errorf、自定義實現(xiàn)了error接口的類型等。

2.1 通過errors.New方法創(chuàng)建

通過該方法創(chuàng)建的錯誤一般是可預(yù)知的錯誤。簡單來說就是調(diào)用者通過該錯誤信息就能明確的知道哪里出錯了,而不需要再額外的添加其他上下文信息,我們在下面的示例中詳細說明。

我們看New方法的實現(xiàn)可知,實際上是返回了一個errorString結(jié)構(gòu)體,該結(jié)構(gòu)體包含了一個字符串屬性,并實現(xiàn)了Error方法。代碼如下:

error.New使用場景1 :

通過errors.New函數(shù)創(chuàng)建局部變量或匿名變量,且不在調(diào)用函數(shù)中進行值或類型判斷的處理,只打印或記錄錯誤日志的場景。

使用示例1 :

以下代碼節(jié)選自源碼/src/net/http/request.go中解析PostForm的部分。 當(dāng)請求中的Body為nil時,返回的錯誤信息是"missing form body"。該信息已明確的說明錯誤是因為請求體為空造成的,所以不需要再額外的添加其他上下文信息。

使用示例2

以下代碼選擇源碼/src/net/http/transport.go的部分,當(dāng)請求體中的url地址為nil返回的錯誤:"http: nil Request.URL" ,說明是請求中的URL字段為nil。以及當(dāng)Header為nil返回的錯誤:"http:nil Request.Header",說明請求體中的Header字段為nil。

error.New使用場景2 :

將errors.New創(chuàng)建的錯誤賦值給一個全局的變量,我們稱該變量為哨兵錯誤,該哨兵錯誤變量可以在被處理的時候使用 == 或 errors.Is來進行值的比較。

使用示例 : 在源碼/src/io/io.go中定義的代表文件末尾的哨兵錯誤變量EOF。

在beego項目中,beego/core/utils/file.go文件中有這樣的應(yīng)用,當(dāng)讀取文件時,遇到的錯誤不是文件末尾的錯誤則直接返回,如果遇到的是文件末尾的錯誤,則中斷for循環(huán),說明文件已經(jīng)讀完文件中的所有內(nèi)容了。如下:

2.2 通過fmt.Errorf方法創(chuàng)建

使用場景1:不帶%w占位符 :

在創(chuàng)建錯誤的時候,不能通過errors.New創(chuàng)建的字符串信息來描述錯誤,而需要通過占位符添加更多的上下文信息,即動態(tài)信息。

使用示例:不帶%w占位符 :

以下示例節(jié)選自gorm/schema/relationship.go的部分代碼,當(dāng)外鍵不合法時,通過fmt.Errorf("invalid foreign key:%s", foreignKey)返回帶具體外鍵的錯誤。因為外鍵值是在運行時才能確定的。代碼如下:

使用場景2:帶%w的占位符 :

在有些場景下,調(diào)用者需要知道原始錯誤信息,一般會通過errors.Is函數(shù)進行判斷該錯誤鏈中是否包含某種特定類型的原始錯誤值。

使用%w占位符創(chuàng)建的錯誤信息,其實會形成一個錯誤鏈。其用法如下:

我們再來看下源代碼:

通過源碼可知,如果fmt.Errorf中包含%w占位符,創(chuàng)建的是一個wrapError結(jié)構(gòu)體類型的值。我們再來看下wrapError結(jié)構(gòu)體的定義:

字段err就是原始錯誤,msg是經(jīng)過格式化之后的錯誤信息。

使用示例:帶%w的占位符 :

假設(shè)我們有一個從數(shù)據(jù)庫查詢合同的函數(shù),當(dāng)從數(shù)據(jù)庫中查詢到記錄為空時,會返回一個sql.ErrNoRows錯誤,我們用%w占位符來wrap該錯誤,并返回給調(diào)用者。

好了,現(xiàn)在GetContract的調(diào)用者可以知道原始的錯誤信息了。在調(diào)用者邏輯中我們可以使用errors.Is來判斷err中是否包含sql.ErrNoRows值了。我們看下調(diào)用者的代碼:

使用場景 :這個是相對errors.New來說的,errors.New適用于對可預(yù)知的錯誤的定義。而當(dāng)發(fā)生了不可預(yù)知的錯誤時,就需要自定義錯誤類型了。

使用示例 : 我們以go源碼/src/io/fs/fs.go文件中的源碼為例,來看下自定義錯誤類型都需要包含哪些元素。

首先看結(jié)構(gòu)體,有一個error接口類型的Err,這個代表的是錯誤源,因為根據(jù)上面講解的,在錯誤層層傳遞返回給調(diào)用者時,我們需要追蹤每一層的原始錯誤信息,所以需要該字段對error進行wrap,形成錯誤鏈。另外,有兩個字段Op和Path,分別代表是產(chǎn)生該錯誤的操作和操作的路徑。這兩個字段就是所謂的未預(yù)料到的錯誤:不確定是針對哪個路徑做了什么錯誤引發(fā)了該錯誤。

我們看下該錯誤類型在代碼中的應(yīng)用:

應(yīng)用1 :在go的文件src/embed/embed.go中的代碼,當(dāng)讀取某目錄時返回的一個PathError類型的錯誤,代表讀取該目錄操作時,因為是一個目錄,所以不能直接讀取文件內(nèi)容。

應(yīng)用2 :在go的文件src/embed/embed.go中的代碼中,有文件讀取的函數(shù),當(dāng)offset小于0時,返回了一個PathError,代表是在讀取該文件的時候,參數(shù)不正確。

fs.ErrInvalid的定義如下:

由此可見,PathError中的三個字段值都是不可預(yù)知的,都需要在程序運行時才能具體決定的,所以這種場景時,則需要自定義錯誤類型。

另外,我們還注意到該自定義的類型中有Unwrap函數(shù)的實現(xiàn),該函數(shù)主要是為了配合errors.Is和errors.As使用的,因為這兩個函數(shù)在使用時是將錯誤鏈層層解包一一比對的。

根據(jù)上一節(jié)我們得到,通過%w占位符可以將錯誤組織成一個錯誤鏈。

errors.Is函數(shù)就是來判斷錯誤鏈中有沒有和指定的錯誤值相等的錯誤,相等于 == 操作符 。注意,這里是特定的錯誤值,就像gorm中定義的ErrRecordNotFound這樣:

那么我們就可以這樣使用errors.Is:

errors.As函數(shù),這個函數(shù)是用來檢查錯誤鏈中的錯誤是否是特定的類型 。如下代碼示例是節(jié)選自etcd項目中etcd/server/embed/config_logging.go中的部分代碼,代表的是err鏈中有沒有能當(dāng)做json.SyntaxError類型的錯誤的,如果能,則將err中的錯誤值賦值到syntaxError變量上,代碼如下:

本文從應(yīng)用場景的角度講解了各種創(chuàng)建錯誤方式的實際應(yīng)用場景。示例中的代碼盡量的選自golang源碼或開源項目。 同時,每種的應(yīng)用場景并非絕對的,需要靈活應(yīng)用。希望本文對大家在實際使用中能夠有所幫助。

基礎(chǔ)知識 - Golang 中的格式化輸入輸出

【格式化輸出】

// 格式化輸出:將 arg 列表中的 arg 轉(zhuǎn)換為字符串輸出

// 使用動詞 v 格式化 arg 列表,非字符串元素之間添加空格

Print(arg列表)

// 使用動詞 v 格式化 arg 列表,所有元素之間添加空格,結(jié)尾添加換行符

Println(arg列表)

// 使用格式字符串格式化 arg 列表

Printf(格式字符串, arg列表)

// Print 類函數(shù)會返回已處理的 arg 數(shù)量和遇到的錯誤信息。

【格式字符串】

格式字符串由普通字符和占位符組成,例如:

"abc%+ #8.3[3]vdef"

其中 abc 和 def 是普通字符,其它部分是占位符,占位符以 % 開頭(注:%% 將被轉(zhuǎn)義為一個普通的 % 符號,這個不算開頭),以動詞結(jié)尾,格式如下:

%[旗標(biāo)][寬度][.精度][arg索引]動詞

方括號中的內(nèi)容可以省略。

【旗標(biāo)】

旗標(biāo)有以下幾種:

空格:對于數(shù)值類型的正數(shù),保留一個空白的符號位(其它用法在動詞部分說明)。

0 :用 0 進行寬度填充而不用空格,對于數(shù)值類型,符號將被移到所有 0 的前面。

其中 "0" 和 "-" 不能同時使用,優(yōu)先使用 "-" 而忽略 "0"。

【寬度和精度】

“寬度”和“精度”都可以寫成以下三種形式:

數(shù)值 | * | arg索引*

其中“數(shù)值”表示使用指定的數(shù)值作為寬度值或精度值,“ ”表示使用當(dāng)前正在處理的 arg 的值作為寬度值或精度值,如果這樣的話,要格式化的 arg 將自動跳轉(zhuǎn)到下一個?!癮rg索引 ”表示使用指定 arg 的值作為寬度值或精度值,如果這樣的話,要格式化的 arg 將自動跳轉(zhuǎn)到指定 arg 的下一個。

寬度值:用于設(shè)置最小寬度。

精度值:對于浮點型,用于控制小數(shù)位數(shù),對于字符串或字節(jié)數(shù)組,用于控制字符數(shù)量(不是字節(jié)數(shù)量)。

對于浮點型而言,動詞 g/G 的精度值比較特殊,在適當(dāng)?shù)那闆r下,g/G 會設(shè)置總有效數(shù)字,而不是小數(shù)位數(shù)。

【arg 索引】

“arg索引”由中括號和 arg 序號組成(就像上面示例中的 [3]),用于指定當(dāng)前要處理的 arg 的序號,序號從 1 開始:

'[' + arg序號 + ']'

【動詞】

“動詞”不能省略,不同的數(shù)據(jù)類型支持的動詞不一樣。

[通用動詞]

v:默認格式,不同類型的默認格式如下:

布爾型:t

整 型:d

浮點型:g

復(fù)數(shù)型:g

字符串:s

通 道:p

指 針:p

無符號整型:x

T:輸出 arg 的類型而不是值(使用 Go 語法格式)。

[布爾型]

t:輸出 true 或 false 字符串。

[整型]

b/o/d:輸出 2/8/10 進制格式

x/X :輸出 16 進制格式(小寫/大寫)

c :輸出數(shù)值所表示的 Unicode 字符

q :輸出數(shù)值所表示的 Unicode 字符(帶單引號)。對于無法顯示的字符,將輸出其轉(zhuǎn)義字符。

U :輸出 Unicode 碼點(例如 U+1234,等同于字符串 "U+%04X" 的顯示結(jié)果)

對于 o/x/X:

如果使用 "#" 旗標(biāo),則會添加前導(dǎo) 0 或 0x。

對于 U:

如果使用 "#" 旗標(biāo),則會在 Unicode 碼點后面添加相應(yīng)的 '字符'(前提是該字符必須可顯示)

[浮點型和復(fù)數(shù)型]

b :科學(xué)計數(shù)法(以 2 為底)

e/E:科學(xué)計數(shù)法(以 10 為底,小寫 e/大寫 E)

f/F:普通小數(shù)格式(兩者無區(qū)別)

g/G:大指數(shù)(指數(shù) = 6)使用 %e/%E,其它情況使用 %f/%F

[字符串或字節(jié)切片]

s :普通字符串

q :雙引號引起來的 Go 語法字符串

x/X:十六進制編碼(小寫/大寫,以字節(jié)為元素進行編碼,而不是字符)

對于 q:

如果使用了 "+" 旗標(biāo),則將所有非 ASCII 字符都進行轉(zhuǎn)義處理。

如果使用了 "#" 旗標(biāo),則輸出反引號引起來的字符串(前提是

字符串中不包含任何制表符以外的控制字符,否則忽略 # 旗標(biāo))

對于 x/X:

如果使用了 " " 旗標(biāo),則在每個元素之間添加空格。

如果使用了 "#" 旗標(biāo),則在十六進制格式之前添加 0x 前綴。

[指針類型]

p :帶 0x 前綴的十六進制地址值。

[符合類型]

復(fù)合類型將使用不同的格式輸出,格式如下:

結(jié) 構(gòu) 體:{字段1 字段2 ...}

數(shù)組或切片:[元素0 元素1 ...]

映 射:map[鍵1:值1 鍵2:值2 ...]

指向符合元素的指針:{}, [], map[]

復(fù)合類型本身沒有動詞,動詞將應(yīng)用到復(fù)合類型的元素上。

結(jié)構(gòu)體可以使用 "+v" 同時輸出字段名。

【注意】

1、如果 arg 是一個反射值,則該 arg 將被它所持有的具體值所取代。

2、如果 arg 實現(xiàn)了 Formatter 接口,將調(diào)用它的 Format 方法完成格式化。

3、如果 v 動詞使用了 # 旗標(biāo)(%#v),并且 arg 實現(xiàn)了 GoStringer 接口,將調(diào)用它的 GoString 方法完成格式化。

如果格式化操作指定了字符串相關(guān)的動詞(比如 %s、%q、%v、%x、%X),接下來的兩條規(guī)則將適用:

4。如果 arg 實現(xiàn)了 error 接口,將調(diào)用它的 Error 方法完成格式化。

5。如果 arg 實現(xiàn)了 string 接口,將調(diào)用它的 String 方法完成格式化。

在實現(xiàn)格式化相關(guān)接口的時候,要避免無限遞歸的情況,比如:

type X string

func (x X) String() string {

return Sprintf("%s", x)

}

在格式化之前,要先轉(zhuǎn)換數(shù)據(jù)類型,這樣就可以避免無限遞歸:

func (x X) String() string {

return Sprintf("%s", string(x))

}

無限遞歸也可能發(fā)生在自引用數(shù)據(jù)類型上面,比如一個切片的元素引用了切片自身。這種情況比較罕見,比如:

a := make([]interface{}, 1)

a[0] = a

fmt.Println(a)

【格式化輸入】

// 格式化輸入:從輸入端讀取字符串(以空白分隔的值的序列),

// 并解析為具體的值存入相應(yīng)的 arg 中,arg 必須是變量地址。

// 字符串中的連續(xù)空白視為單個空白,換行符根據(jù)不同情況處理。

// \r\n 被當(dāng)做 \n 處理。

// 以動詞 v 解析字符串,換行視為空白

Scan(arg列表)

// 以動詞 v 解析字符串,換行結(jié)束解析

Scanln(arg列表)

// 根據(jù)格式字符串中指定的格式解析字符串

// 格式字符串中的換行符必須和輸入端的換行符相匹配。

Scanf(格式字符串, arg列表)

// Scan 類函數(shù)會返回已處理的 arg 數(shù)量和遇到的錯誤信息。

【格式字符串】

格式字符串類似于 Printf 中的格式字符串,但下面的動詞和旗標(biāo)例外:

p :無效

T :無效

e/E/f/F/g/G:功能相同,都是掃描浮點數(shù)或復(fù)數(shù)

s/v :對字符串而言,掃描一個被空白分隔的子串

對于整型 arg 而言,v 動詞可以掃描帶有前導(dǎo) 0 或 0x 的八進制或十六進制數(shù)值。

寬度被用來指定最大掃描寬度(不會跨越空格),精度不被支持。

如果 arg 實現(xiàn)了 Scanner 接口,將調(diào)用它的 Scan 方法掃描相應(yīng)數(shù)據(jù)。只有基礎(chǔ)類型和實現(xiàn)了 Scanner 接口的類型可以使用 Scan 類方法進行掃描。

【注意】

連續(xù)調(diào)用 FScan 可能會丟失數(shù)據(jù),因為 FScan 中使用了 UnreadRune 對讀取的數(shù)據(jù)進行撤銷,而參數(shù) io.Reader 只有 Read 方法,不支持撤銷。比如:

文章標(biāo)題:go語言占位符作用_ go 占位符
網(wǎng)址分享:http://muchs.cn/article12/ddcsegc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、網(wǎng)站設(shè)計、動態(tài)網(wǎng)站網(wǎng)站內(nèi)鏈、全網(wǎng)營銷推廣網(wǎng)站改版

廣告

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

綿陽服務(wù)器托管