W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
原文鏈接:https://gopl-zh.github.io/ch7/ch7-04.html
在本章,我們會(huì)學(xué)到另一個(gè)標(biāo)準(zhǔn)的接口類型flag.Value是怎么幫助命令行標(biāo)記定義新的符號(hào)的。思考下面這個(gè)會(huì)休眠特定時(shí)間的程序:
gopl.io/ch7/sleep
var period = flag.Duration("period", 1*time.Second, "sleep period")
func main() {
flag.Parse()
fmt.Printf("Sleeping for %v...", *period)
time.Sleep(*period)
fmt.Println()
}
在它休眠前它會(huì)打印出休眠的時(shí)間周期。fmt包調(diào)用time.Duration的String方法打印這個(gè)時(shí)間周期是以用戶友好的注解方式,而不是一個(gè)納秒數(shù)字:
$ go build gopl.io/ch7/sleep
$ ./sleep
Sleeping for 1s...
默認(rèn)情況下,休眠周期是一秒,但是可以通過(guò) -period 這個(gè)命令行標(biāo)記來(lái)控制。flag.Duration函數(shù)創(chuàng)建一個(gè)time.Duration類型的標(biāo)記變量并且允許用戶通過(guò)多種用戶友好的方式來(lái)設(shè)置這個(gè)變量的大小,這種方式還包括和String方法相同的符號(hào)排版形式。這種對(duì)稱設(shè)計(jì)使得用戶交互良好。
$ ./sleep -period 50ms
Sleeping for 50ms...
$ ./sleep -period 2m30s
Sleeping for 2m30s...
$ ./sleep -period 1.5h
Sleeping for 1h30m0s...
$ ./sleep -period "1 day"
invalid value "1 day" for flag -period: time: invalid duration 1 day
因?yàn)闀r(shí)間周期標(biāo)記值非常的有用,所以這個(gè)特性被構(gòu)建到了flag包中;但是我們?yōu)槲覀冏约旱臄?shù)據(jù)類型定義新的標(biāo)記符號(hào)是簡(jiǎn)單容易的。我們只需要定義一個(gè)實(shí)現(xiàn)flag.Value接口的類型,如下:
package flag
// Value is the interface to the value stored in a flag.
type Value interface {
String() string
Set(string) error
}
String方法格式化標(biāo)記的值用在命令行幫助消息中;這樣每一個(gè)flag.Value也是一個(gè)fmt.Stringer。Set方法解析它的字符串參數(shù)并且更新標(biāo)記變量的值。實(shí)際上,Set方法和String是兩個(gè)相反的操作,所以最好的辦法就是對(duì)他們使用相同的注解方式。
讓我們定義一個(gè)允許通過(guò)攝氏度或者華氏溫度變換的形式指定溫度的celsiusFlag類型。注意celsiusFlag內(nèi)嵌了一個(gè)Celsius類型(§2.5),因此不用實(shí)現(xiàn)本身就已經(jīng)有String方法了。為了實(shí)現(xiàn)flag.Value,我們只需要定義Set方法:
gopl.io/ch7/tempconv
// *celsiusFlag satisfies the flag.Value interface.
type celsiusFlag struct{ Celsius }
func (f *celsiusFlag) Set(s string) error {
var unit string
var value float64
fmt.Sscanf(s, "%f%s", &value, &unit) // no error check needed
switch unit {
case "C", "°C":
f.Celsius = Celsius(value)
return nil
case "F", "°F":
f.Celsius = FToC(Fahrenheit(value))
return nil
}
return fmt.Errorf("invalid temperature %q", s)
}
調(diào)用fmt.Sscanf函數(shù)從輸入s中解析一個(gè)浮點(diǎn)數(shù)(value)和一個(gè)字符串(unit)。雖然通常必須檢查Sscanf的錯(cuò)誤返回,但是在這個(gè)例子中我們不需要。因?yàn)槿绻绣e(cuò)誤發(fā)生,就沒(méi)有switch case會(huì)匹配到。
下面的CelsiusFlag函數(shù)將所有邏輯都封裝在一起。它返回一個(gè)內(nèi)嵌在celsiusFlag變量f中的Celsius指針給調(diào)用者。Celsius字段是一個(gè)會(huì)通過(guò)Set方法在標(biāo)記處理的過(guò)程中更新的變量。調(diào)用Var方法將標(biāo)記加入應(yīng)用的命令行標(biāo)記集合中,有異常復(fù)雜命令行接口的全局變量flag.CommandLine.Programs可能有幾個(gè)這個(gè)類型的變量。調(diào)用Var方法將一個(gè)*celsiusFlag
參數(shù)賦值給一個(gè)flag.Value參數(shù),導(dǎo)致編譯器去檢查*celsiusFlag
是否有必須的方法。
// CelsiusFlag defines a Celsius flag with the specified name,
// default value, and usage, and returns the address of the flag variable.
// The flag argument must have a quantity and a unit, e.g., "100C".
func CelsiusFlag(name string, value Celsius, usage string) *Celsius {
f := celsiusFlag{value}
flag.CommandLine.Var(&f, name, usage)
return &f.Celsius
}
現(xiàn)在我們可以開始在我們的程序中使用新的標(biāo)記:
gopl.io/ch7/tempflag
var temp = tempconv.CelsiusFlag("temp", 20.0, "the temperature")
func main() {
flag.Parse()
fmt.Println(*temp)
}
下面是典型的場(chǎng)景:
$ go build gopl.io/ch7/tempflag
$ ./tempflag
20°C
$ ./tempflag -temp -18C
-18°C
$ ./tempflag -temp 212°F
100°C
$ ./tempflag -temp 273.15K
invalid value "273.15K" for flag -temp: invalid temperature "273.15K"
Usage of ./tempflag:
-temp value
the temperature (default 20°C)
$ ./tempflag -help
Usage of ./tempflag:
-temp value
the temperature (default 20°C)
練習(xí) 7.6: 對(duì)tempFlag加入支持開爾文溫度。
練習(xí) 7.7: 解釋為什么幫助信息在它的默認(rèn)值是20.0沒(méi)有包含°C的情況下輸出了°C。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: