我遇到过一个场景,我必须使用一个变量来计算,比方说255或65535(取决于一个标志)并溢出到0.所以当我设置标志为say,true时,类型定义应该是uint8,当为false时,类型定义应该是uint16。显然我可以将主变量设置为uint16并对它们执行数学操作,但是有没有本机解决方案呢?
答案 0 :(得分:3)
Go是一种静态类型语言,这意味着必须在编译时知道变量类型,并且不能在运行时更改它们的类型。
而是使用负责增加其值的方法创建自己的counter
类型,这可以检查是否超出了计数器的最大值,在这种情况下它可以重置它。
type Counter struct {
value, Max int
}
func (c *Counter) Inc() {
c.value++
if c.value > c.Max {
c.value = 0
}
}
func (c *Counter) Value() int { return c.value }
使用它的示例:
c := &Counter{Max: 255}
for i := 0; i < 257; i++ {
c.Inc()
if i > 252 {
fmt.Println(c.Value())
}
}
输出(在Go Playground上尝试):
254
255
0
1
所以在你的情况下使用它:
c := &Counter{}
if flagUse8bit {
c.Max = 0xff
} else {
c.Max = 0xffff
}
另一个不错的解决方案是使用接口,因为接口类型的变量可以保存实现该接口的任何类型的值。
创建Counter
接口类型:
type Counter interface {
Inc()
Value() int
}
对于不同的类型有不同的实现,只需使用不同的底层类型,利用溢出将自然发生的事实。您可以根据CLI标志值选择要存储在Counter
接口变量中的运行时类型。
type counter8 uint8
func (c *counter8) Inc() { *c++ }
func (c counter8) Value() int { return int(c) }
type counter16 uint16
func (c *counter16) Inc() { *c++ }
func (c counter16) Value() int { return int(c) }
使用它:
var c Counter
c = new(counter8)
for i := 0; i < 257; i++ {
c.Inc()
if i > 252 {
fmt.Println(c.Value())
}
}
c = new(counter16)
for i := 0; i < 65537; i++ {
c.Inc()
if i > 65532 {
fmt.Println(c.Value())
}
}
输出(在Go Playground上尝试):
254
255
0
1
65534
65535
0
1
所以在你的情况下使用它:
var c Counter
if flagUse8bit {
c = new(counter8)
} else {
c = new(counter16)
}