Go语言圣经 - 第7章 接口 - 7.4 flag.Value接口

第7章 接口

接口类型是对其它类型行为的抽象和概括.接口类型不会和特定的实现细节绑定在一起,这种抽象的方式能让我们的函数更加的灵活和更具有适应能力

Go语言的接口比较特殊,因为它是满足隐式实现的。也就是说,我们无需给具体类型定义所有满足足的接口类型,只需要让类型拥有一些简单必要的方法。这样我们新建一个接口类型,满足具体类型,并且我们不需要更改这些类型的定义。当我们使用的类型来自于不受我们控制的包时,这种机制比较有用

7.4 flag.Value接口

我们来看一个标准的接口类型flag.Value,它能够帮助命令行标记定义新符号,看看下面这个会休眠特定时间的程序

var period = flag.Duration("period",1*time.Second,"sleep period")

func main() {
	flag.Parse()
	fmt.Printf("sleep for %v...",*period)
	time.Sleep(*period)
	fmt.Println()
}

运行上述代码,输出的是一个非常友好的结果

C:\Users\xxx\GolandProjects\awesomeProject\src\chapter7>go run sleep.go
sleep for 1s...

默认的休眠是1s,但是我们可以通过 -period这个命令行标记来控制flag.Duration函数创建一个time.Duration类型的标记变量并且允许用户通过多种用户友好的方式来设置这个变量的大小。这种方法还包括和string方法相同的符号排版形式,这种对称设计使得用户交互良好

C:\Users\xxx\GolandProjects\awesomeProject\src\chapter7>go run sleep.go -period 50ms
sleep for 50ms...
C:\Users\xxx\GolandProjects\awesomeProject\src\chapter7>go run sleep.go -period "1h"
sleep for 1h0m0s...

因为时间周期标记值非常有用, 所以这个特性被构建到了flag包中,但是我们为自己的自定义类型定义一个新的标记符号时非常容易的,我们只需要定义一个实现flag.Value接口的类型,如下:

package flag
// Value is the interface to the value stored in a flag
Type Vlaue interface {
	String() string
	Set(string) error
}

String方法格式化标记的值用在命令行帮助消息中;这样每一个flag.Value也是一个fmt.Stringer.Set方法解析它的字符串参数并且更新标记变量的值,实际上,Set方法和String是两个相反的操作,所以最好的办法就是对它们使用相同的注解方式

定义一个允许通过摄氏度或者华氏温度变换的形式指定温度的celsiusFlag类型,注意celsiusFlag内嵌了一个Celsius类型,因此不用实现本身就已经有String方法了,为了实现flag.Value,我们只需要定义Set方法:

//*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)
	switch unit {
	case "C","℃":
		f.Celsius = Celsius(value)
		return nil
	case "F","℉":
		f.Celsius = FToC(Fahrenheit(value))
		return nil
	}
	return fmt.Errorf("invalid temperature %q",s)
}

调用fmt.Sscanf函数从输入s中解析一个浮点数(value)和一个字符串(unit)。虽然通常必须检查Sscanf的错误返回,但是在这个例子中,我们不需要,因为如果有错误发生,就没有switch case匹配到

下面的CelsiusFlag函数将所有逻辑都封装在一起,它返回一个内嵌在celsiusFlag变量f中的Celsius指针给调用者

Celsius字段是一个会通过Set方法在标记处理的过程中更新的变量。调用Var方法将标记加入应用的命令行标记集合中,有异常复杂的命令行接口的全局变量flag.CommandLine.Programs可能有几个这个类型的变量。调用Var方法将一个*celsiusFlag参数赋值给一个flag.Value参数,导致编译器去检查 *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
}

现在我们可以在程序中使用新的标记

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言圣经》是一本广受好评的教材,旨在帮助读者系统地学习和掌握Go语言。这本书以简明清晰的方式介绍了Go语言的各种特性、语法和用法,是入门和进阶者的理想选择。 首先,该书提供了对Go语言基础知识的全面介绍。它从简单到复杂地解释了Go语言的基本概念,诸如变量、函数、循环和条件语句等等。通过丰富的例子和练习,读者能够逐步理解和掌握这些概念。 其次,该书详细介绍了Go语言的高级特性和用法。读者可以学习到Go语言的面向对象编程、并发编程、网络编程等关键技术。并发编程是Go语言的一个独特特性,对于提高程序性能和扩展能力非常重要。 此外,该书还包含了对常见问题和陷阱的讲解,帮助读者避免一些常见的错误和陷阱。同时,书中提供了大量的案例和实践项目,读者可以通过实际操作来巩固所学内容。 《Go语言圣经》以其简洁明了的风格和对细节的深入讲解而闻名。无论是作为初学者的入门指南,还是作为有经验的开发者的参考书,这本书都能满足读者的需求。此外,该书的PDF版本能够方便地在线或离线阅读,为读者提供了更加便捷的学习体验。 综上所述,《Go语言圣经》是一本内容丰富、权威性强的优秀教材。它不仅适合Go语言的初学者,也适用于那些想要深入学习和掌握Go语言开发者。无论是在线阅读还是PDF版本,读者都能够方便地获取和利用这本宝贵的学习资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值