W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
原文鏈接:https://gopl-zh.github.io/ch7/ch7-04.html
在本章,我們會學到另一個標準的接口類型flag.Value是怎么幫助命令行標記定義新的符號的。思考下面這個會休眠特定時間的程序:
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()
}
在它休眠前它會打印出休眠的時間周期。fmt包調用time.Duration的String方法打印這個時間周期是以用戶友好的注解方式,而不是一個納秒數(shù)字:
$ go build gopl.io/ch7/sleep
$ ./sleep
Sleeping for 1s...
默認情況下,休眠周期是一秒,但是可以通過 -period 這個命令行標記來控制。flag.Duration函數(shù)創(chuàng)建一個time.Duration類型的標記變量并且允許用戶通過多種用戶友好的方式來設置這個變量的大小,這種方式還包括和String方法相同的符號排版形式。這種對稱設計使得用戶交互良好。
$ ./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
因為時間周期標記值非常的有用,所以這個特性被構建到了flag包中;但是我們?yōu)槲覀冏约旱臄?shù)據(jù)類型定義新的標記符號是簡單容易的。我們只需要定義一個實現(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方法格式化標記的值用在命令行幫助消息中;這樣每一個flag.Value也是一個fmt.Stringer。Set方法解析它的字符串參數(shù)并且更新標記變量的值。實際上,Set方法和String是兩個相反的操作,所以最好的辦法就是對他們使用相同的注解方式。
讓我們定義一個允許通過攝氏度或者華氏溫度變換的形式指定溫度的celsiusFlag類型。注意celsiusFlag內嵌了一個Celsius類型(§2.5),因此不用實現(xiàn)本身就已經有String方法了。為了實現(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)
}
調用fmt.Sscanf函數(shù)從輸入s中解析一個浮點數(shù)(value)和一個字符串(unit)。雖然通常必須檢查Sscanf的錯誤返回,但是在這個例子中我們不需要。因為如果有錯誤發(fā)生,就沒有switch case會匹配到。
下面的CelsiusFlag函數(shù)將所有邏輯都封裝在一起。它返回一個內嵌在celsiusFlag變量f中的Celsius指針給調用者。Celsius字段是一個會通過Set方法在標記處理的過程中更新的變量。調用Var方法將標記加入應用的命令行標記集合中,有異常復雜命令行接口的全局變量flag.CommandLine.Programs可能有幾個這個類型的變量。調用Var方法將一個*celsiusFlag
參數(shù)賦值給一個flag.Value參數(shù),導致編譯器去檢查*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)在我們可以開始在我們的程序中使用新的標記:
gopl.io/ch7/tempflag
var temp = tempconv.CelsiusFlag("temp", 20.0, "the temperature")
func main() {
flag.Parse()
fmt.Println(*temp)
}
下面是典型的場景:
$ 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)
練習 7.6: 對tempFlag加入支持開爾文溫度。
練習 7.7: 解釋為什么幫助信息在它的默認值是20.0沒有包含°C的情況下輸出了°C。
![]() | ![]() |
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: