枚举

定义枚举

枚举默认是模块内访问,通过pub关键字来定义公共枚举。

枚举的命名跟结构体命名一样,必须以大写字母开头,枚举项的名称跟函数命名一样,必须是小写加下划线。

enum Color {
	blue // 如果没有指定初始值,默认从0开始,然后往下递增1
	green
	white
	black
}

fn main() {
	mut c := Color.green // 第一次定义要使用:枚举名称.枚举值
	println(c) // 输出green
	c = Color.blue
	c = .blue // 第二次修改赋值,也可以忽略枚举名称,直接使用.枚举值就可以了
	println(c) // 输出blue
}

也可以指定枚举值的值,枚举值也可以是负数:

enum Color2 {
	blue = 2 //可以指定初始值
	green
	white
	black
}

enum Color3 {
	blue = -4 //初始值也可以是负数
	green
	white
	black
}

fn main() {
	mut c := Color2.green
	println(c) //输出green
	c = .blue
	println(c) //输出blue
}

也可以指定枚举的值为16进制:

enum W_hex {
	a = 0x001 //枚举值也支持16进制
	b = 0x010
	c = 0x100
}

fn main() {
	println(W_hex.a) //输出a
	println(W_hex.b) //输出b
	println(W_hex.c) //输出c
}

枚举值类型

枚举值默认是int类型,也可以使用as来明确指定枚举值的类型,枚举值的类型只能是内置的整数类型。

enum Color { //默认是int类型
	red
	green = 2147483646
	blue
}

enum ColorI8 as i8 {
	red
	green = 126
	blue
}

enum ColorI16 as i16 {
	red
	green = 32766
	blue
}

enum ColorI32 {
	red
	green = 2147483646
	blue
}

enum ColorI64 as i64 {
	red
	green = 9223372036854775806
	blue
}

enum ColorU8 as u8 {
	green = 127
}

enum ColorU16 as u16 {
	green = 32768
}

enum ColorU32 as u32 {
	green = 2147483647
}

enum ColorU64 as u64 {
	green = 9223372036854775807
}

枚举方法

枚举也可以像结构体那样添加方法:

enum Color {
	red = 1
	green
	blue
	black
	white
}

fn (c Color) is_blue() bool { // 枚举方法
	return c == .blue
}

fn main() {
	b := Color.blue
	if b.is_blue() {
		println('yes')
		println(b)
	} else {
		println('no')
		println(b)
	}
}

枚举值/整型相互转换

枚举类型和整数类型可以相互转换,不过有一点需要特别注意,将整数转换为枚举类型,属于跨类型的强制转换,必须在不安全代码块中执行,不然编译器会报错。

enum Color {
	red = 1
	green
	blue
	black
	white
}

fn main() {
	i := 3 // 推断为int
	// println(i==.blue) 	//报错,类型不匹配
	e := unsafe { Color(i) } // 将整数转换为枚举类型,属于跨类型的强制转换,必须在不安全代码块中
	println(e == .blue) // 输出true
	ii := int(e) // 枚举类型转换为int
	println(ii) // 输出3
	iii := e // iii是枚举类型
	println(typeof(iii).name)
	println(iii)
}

枚举类型数组

可以定义枚举类型的数组,数组的值是某个枚举项:

struct Abc {
mut:
	flags []Flag
}

enum Flag {
	flag_one
	flag_two
	flag_three
}

fn main() {
	mut a := Abc{}
	a.flags << .flag_one
	a.flags << .flag_two
	a.flags << .flag_three
	println(a.flags)
}

遍历枚举值

可以使用$for in语句来遍历所有的枚举值:

enum Color {
	red = 1
	green
	blue
}

fn main() {
	$for e in Color.values { // $for in语句可以用来遍历所有的枚举值,内置的values,表示所有的枚举值,
		if e.name == 'red' { //内置的name,表示当前枚举名
			println(e.value == Color.red) //内置的value,表示当前枚举值
		} else if e.name == 'green' {
			println(e.value == Color.green)
		} else if e.name == 'blue' {
			println(e.value == Color.blue)
		}
	}
}

枚举注解

@[flag]注解

如果给枚举加了@[flag]注解,就表示这个枚举是位字段类型的枚举,枚举项的值不能自定义设置,由编译器自动设置,按顺序是2的n次方,n从0开始:1,2,4,8,16 ...。

如果枚举是位字段类型的枚举,可以使用以下内置方法:

has() //判断枚举项是否包含参数中的某一项值
all() //判断枚举项是否等于参数的所有值
set() //在枚举项已有值的基础上,追加参数的值,为什么不用append更准确?
toggle() //在枚举项已有值的基础上,去掉参数的值,为什么不用delete更准确?
clear()  //跟toggle一样
is_empty() //判断枚举值是否为空,如果枚举的值都被清空了,返回true
@[flag]
enum BitField { //编译器自动设置枚举项的值
	read
	write
	delete
	other
}

fn main() {
	println(1 == int(BitField.read)) // true
	println(2 == int(BitField.write)) // true
	println(4 == int(BitField.delete)) // true
	println(8 == int(BitField.other)) // true
	mut bf := BitField.read
	println(bf.has(.read | .other)) // true,测试bf枚举值是否包含参数的某一个值
	println(bf.all(.read | .other)) // false,测试bf枚举值是否等于参数的所有值
	bf.set(.write | .other) //在枚举项已有值的基础上,追加.write和.other
	println(bf) //.read | .write | .other
	println(bf.has(.read | .write | .other)) // true
	println(bf.all(.read | .write | .other)) // true
	bf.toggle(.other) //在枚举项已有值的基础上,去掉.other
	println(bf) //.read | .write
	println(bf == BitField.read | .write) // false
	println(bf.all(.read | .write)) // true
	println(bf.has(.other)) // false
	println(bf.has(.read)) // true
	bf.clear(.read) // 跟toggle一样
	bf.clear(.write) // 跟toggle一样
	println(bf.is_empty()) // 判断枚举项是否为空,true
	println(bf)
}

自定义注解

可以像结构体和函数那样,给枚举和枚举值添加自定义注解,然后自己解析使用。

关于注解的进一步使用,可以参考注解章节

枚举注解:

@[attr1]
@[attr2]
pub enum Color {
	black 【attr3
	white
	blue
}

枚举值注解:

enum Color {
	red = 1 + 1  [json: 'Red'] //枚举值注解
	blue = 10 / 2  [json: 'Blue']
}

fn main() {
	$for e in Color.values {
		if e.name == 'red' {
			println(e.value == Color.red)
		} else if e.name == 'blue' {
			println(e.value == Color.blue)
		}
	}
}

最后更新于