本篇内容主要讲解“Go中怎么正确使用对枚举”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Go中怎么正确使用对枚举”吧!
枚举是强类型编程语言中的一种类型,由一组名称和值组成。通常用来在编程语言中充当常量的标识符。
没毛病,我们也确实是这样使用的。比如上学的时候,经常写c的小玩具代码,c标准里面提供了enum关键字,写起来比较直白,使用的时候和struct类似,需要enum week这样写,c里面默认枚举值是从0开始,int类型,其实c里面就是把枚举当做int类型来用的。
#include<stdio.h> enum week{Mon, Tue, Wed, Thur, Fri, Sat, Sun}; int main() { enum week day; // 需要加 enum 关键字 day = Wed; printf("%d",day); // 输出 2 int i; for (i=Mon; i<=Sun; i++){ // 可以直接把枚举类型赋值给int类型 printf("%d ", i); // 输出 0,1,2,3,4,5,6 } return 0; }
上面的例子没问题,在初始化的时候,枚举值默认情况下,编译器会从分配0开始的值,例如上面的Mon=0,Tue=1…,但是也会想不按照编译器的默认分配方式,由我自己分配,那怎么写呢,看下面的例子:
#include <stdio.h> enum day {sunday = 1, monday, tuesday = 5, wednesday, thursday = 10, friday, saturday}; int main() { printf("%d %d %d %d %d %d %d", sunday, monday, tuesday, wednesday, thursday, friday, saturday); // 输出1 2 5 6 10 11 12 return 0; }
也就是说,枚举里面可以按任何顺序将值分配给某个名称。所有未分配的名称都会把值作为前一个名称的值加一。
其实,定义几个常量的事,是不是用宏这个东西更好呢,比如这么写
#define sunday 0 #define monday 1 #define tuesday 2
但是老师说了,尽量别用宏,不是说宏不好,宏也好,编译器替换,没有运行期啥事,多快啊,但是有几个问题:
1)宏没有作用域一说 2)枚举是类型安全的
扯的有点远了,现在回来看看Go里面的枚举怎么写。当然也很简单了,官方教导我们这么写:
type ByteSize float64 const ( _ = iota KB ByteSize = 1 << (10 * iota) MB GB )
Go里面更简洁了,直接把enum关键字去掉了,其实从Go的角度看,枚举不就是常量么,搞这么多语法糖干嘛,Go里面提供了一个关键字iota可以实现常量的递增,同时也支持手动赋值,iota和手动赋值结合起来,就可以实现类似c里面的效果
const ( A0 = iota A1 = iota A2 = iota ) fmt.Println(A0, A1, A2) // "0 1 2"
可以 简写成这样
const ( A0 = iota A1 A2 )
也可以从1开始
const ( A1 = iota + 1 A2 A3 ) fmt.Println(A1, A2, A3) // "1 2 3"
或者跳过某个值
const ( C1 = iota + 1 _ C3 C4 ) fmt.Println(C1, C3, C4) // "1 3 4"
看到这里你或许有个疑问,这里的枚举其实就是常量么,那怎么写是字符串类型的枚举呢,你可能会说,当然是用字符串常量了。但是那只是字符串常量了,没有枚举的性质。我可能想要的是一种字符串到值的枚举类型。思考再三,看我这种写法是否可以:
-
步骤一:创建一个新的int类型
-
步骤二:使用iota表示值
-
步骤三:给这个新的类型一个String的方法
type Direction int const ( North Direction = iota East South West ) func (d Direction) String() string { return [...]string{"North", "East", "South", "West"}[d] }
使用的时候
var d Direction = North fmt.Print(d) switch d { case North: fmt.Println(" goes up.") case South: fmt.Println(" goes down.") default: fmt.Println(" stays put.") }
当然还有一种方法,比较stupid
type weekday string func (w weekday) isWeekday() weekday { return w } type Weekday interface { isWeekday() weekday } const ( Monday = weekday("Monday") Tuesday = weekday("Tuesday") Wendsday = weekday("Wendsday") Thursday = weekday("Thursday") Friday = weekday("Friday") Saturday = weekday("Saturday") Sunday = weekday("Sunday") ) // 使用 func main() { var d1 = weekday.Monday var d2 = weekday.Tuesday fmt.Println(d1, d2, d1 == d2, d1 == weekday.Monday) }
如果使用struct表示枚举,那其实还可以使用反射的方式,比如下面这样写:
import ( "reflect" ) type weekday struct { Monday, Tuesday, Wendsday, Thursday, Friday, Saturday, Sunday int } func (c weekday) Get(id string) int { vo := reflect.ValueOf(c) typeVo := vo.Type() for i := 0; i < vo.NumField(); i++ { if typeVo.Field(i).Name == id { return vo.Field(i).Interface().(int) } } return 0 } var weekdayEnum = weekday { Monday: 1, Tuesday: 2, Wendsday: 3, Thursday: 4, Friday: 5, Saturday: 6, Sunday: 7 }