C/C++中枚举类型(enum)
如果一个变量你需要几种可能存在的值,那么就可以被定义成为枚举类型。之所以叫枚举就是说将变量或者叫对象可能存在的情况也可以说是可能的值一一例举出来。 举个例子来说明一吧,为了让大家更明白一点,比如一个铅笔合中有一支笔,但在没有打开之前你并不知道它是什么笔,可能是铅笔也可能是钢笔,这里有两种可能,那么你就可以定义一个枚举类型来表示它! enum box{pencil,pen};//这里你就定义了一个枚举类型的变量叫box,这个枚举变量内含有两个元素也称枚举元素在这里是pencil和pen,分别表示铅笔和钢笔。
在这里要说一下,如果你想定义两个具有同样特性枚举类型的变量那么你可以用如下的两种方式进行定义! enum box{pencil,pen}; enum box box2;//或者简写成box box2;
再有一种就是在声明的时候同时定义。 enum {pencil,pen}box,box2; //在声明的同时进行定义!
枚举变量中的枚举元素系统是按照常量来处理的,故叫枚举常量,他们是不能进行普通的算术赋值的,(pencil=1;)这样的写发是错误的,但是你可以在声明的时候进行赋值 *** 作! enum box{pencil=1,pen=2};
但是这里要特别注意的一点是,如果你不进行元素赋值 *** 作那么元素将会被系统自动从0开始自动递增的进行赋值 *** 作,说到自动赋值,如果你只定义了第一个那么系统将对下一个元素进行前一个元素的值加1 *** 作,例如 enum box{pencil=3,pen};//这里pen就是4系统将自动进行pen=4的定义赋值 *** 作!
C++ 中的枚举类型继承于 C 语言。就像其他从 C 语言继承过来的很多特性一样,C++ 枚举也有缺点,这其中最显著的莫过于作用域问题——在枚举类型中定义的常量,属于定义枚举的作用域,而不属于这个枚举类型。例如下面的示例:enum FileAccess {
Read = 0x1,
Write = 0x2,
};FileAccess access = ::Read; // 正确
FileAccess access = FileAccess::Read; // 错误C++枚举的这个特点对于习惯面向对象和作用域概念的人来说是不可接受的。首先,FileAccess::Read 显然更加符合程序员的直觉,因为上面的枚举定义理应等价于如下的定义(实际上,NET 中的枚举类型便是如此实现的):class FileAccess {
static const int Read = 0x1;
static const int Write = 0x2;
};其次,这导致我们无法在同一个作用域中定义两个同样名称的枚举值。也就是说,以下的代码是编译错误:enum FileAccess {
Read = 0x1,
Write = 0x2,
};enum FileShare {
Read = 0x1, // 重定义
Write = 0x2, // 重定义
};如果这一点没有让你恼怒过的话,你可能还没写过多少 C++ 代码 :-)。实际上,在最新的 C++0x 标准草案中有关于枚举作用域问题的提案,但最终的解决方案会是怎样的就无法未卜先知了,毕竟对于象 C++ 这样使用广泛的语言来说,任何特性的增删和修改都必须十分小心谨慎。当然,我们可以使用一些迂回的方法来解决这个问题(C++ 总是能给我们很多惊喜和意外)。例如,我们可以把枚举值放在一个结构里,并使用运算符重载来逼近枚举的特性:struct FileAccess {
enum __Enum {
Read = 0x1,
Write = 0x2
};
__Enum _value; // 枚举值 FileAccess(int value = 0) : _value((__Enum)value) {}
FileAccess& operator=(int value) {
this->_value = (__Enum)value;
return this;
}
operator int() const {
return this->_value;
}
};我们现在可以按照希望的方式使用这个枚举类型:FileAccess access = FileAccess::Read;并且,因为我们提供了到 int 类型的转换运算符,因此在需要 int 的地方都可以使用它,例如 switch 语句:switch (access) {
case FileAccess::Read:
break;
case FileAccess::Write:
break;
}当然我们不愿意每次都手工编写这样的结构。通过使用宏,我们可以很容易做到这一点:#define DECLARE_ENUM(E) \
struct E \
{ \
public: \
E(int value = 0) : _value((__Enum)value) { \
} \
E& operator=(int value) { \
this->_value = (__Enum)value; \
return this; \
} \
operator int() const { \
return this->_value; \
} \
\
enum __Enum {#define END_ENUM() \
}; \
\
private: \
__Enum _value; \
};我们现在可以按如下的方式定义前面的枚举,并且不比直接写 enum 复杂多少。DECLARE_ENUM(FileAccess)
Read = 0x1,
Write = 0x2,
END_ENUM()DECLARE_ENUM(FileShare)
Read = 0x1,
Write = 0x2,
END_ENUM()
Swift基础语法总结,来自 苹果官方文档 :
枚举在Swift中是 first-class types。与C,Objective-C中的枚举相比,Swift中枚举功能更强大。它支持很多只有类才有的特性,如: Properties , Methods , Initialization , Extensions , Protocols
举例:
通常将单个枚举值与switch语句匹配:
当需要迭代枚举中的所有情况时,需要自定义的枚举遵守 CaseIterable 协议
我们可以定义Swift枚举来存储任何给定类型的关联值,而且每种枚举情况的值类型可以不同。
可以将关联值提取为switch语句的一部分。将每个关联值提取为常量(let)或变量(var),以便在switch中处理:
如果枚举case的所有关联值都被提取为常量,或者都被提取为变量,则可以将var或let放置在case名称前面,来提取所有的关联值:
“ 关联值 ”表明了枚举如何存储不同类型的关联值。作为关联值的替代,枚举情况可以预先设置默认值(称 原始值 ),它们都是相同的类型。
原始值可以是字符串,字符,整数或浮点数类型。每个原始值在其枚举声明中必须是唯一的。
当使用存储整数或字符串原始值的枚举时,不必为每种case显式分配原始值,Swift将自动为其分配值。如果使用整数为原始值,则每个case的原始值依次自增1。若第一个case没有设置原始值,则默认为0:
当使用字符串作为原始值时,每个case的隐含值是该case的名称。
使用枚举的 rawValue 属性来访问其原始值:
如果使用原始值类型定义枚举,则枚举会自动接收一个带有原始值的初始化器,并返回可选类型的枚举实例。
递归枚举是将枚举的另一个实例作为一个或多个枚举case的关联值。在枚举case 前面添加关键字 indirect 来指明该枚举case是递归的,这就告诉了编译器插入必要的间接层。
例如,下面是存储简单算术表达式的枚举:
还可以在枚举 enum 之前添加 indirect ,以便为所有具有关联值的枚举case启用间接:
递归函数是处理具有递归结构的数据的简单方法。例如,这是一个计算算术表达式的函数:
Swift 42 基础专题详解
var obj = {name:"张三",age:18}
for(var key in obj){
consolelog("key:" + key + ",value:" + obj[key]);
}
//输出:key:name,value:张三和key:age,value:18
//这里的可枚举性就是说for的这种写法可以得到这个对象的属性名
var obj1 = {};
ObjectdefineProperties(obj1, {
name: {
value: "张三",
enumerable: false
},
age: {
value: 18,
enumerable: false
}
});
for(var key in obj1){
consolelog("key:" + key + ",value:" + obj[key]);
}
//这里不会输出任何东西,但是可以用obj1name和obj1age直接取值。
//当然obj1["name"]也是可以得到张三的。
//但是不能用for来枚举出他有什么属性。
//以上代码请在chrome或者火狐里面运行,IE9以下运行第二段代码会出错
结果:Mr John Doe
转的。枚举是一个特殊的类。
枚举类型是JDK50的新特征 。Sun引进了一个全新的关键字enum来定义一个枚举类 。下面就是一个典型枚举类型的定义:
Java代码:
public enum Color{
RED,BLUE,BLACK,YELLOW,GREEN
}
显然,enum很像特殊的class,实际上enum声明定义的类型就是一个类 。 而这些类都是类库中Enum类的子类(javalangEnum) 。它们继承了这个Enum中的许多有用的方法 。我们对代码编译之后发现,编译器将enum类型单独编译成了一个字节码文件:Colorclass 。
Color字节码代码
final enum hrtestColor {
// 所有的枚举值都是类静态常量
public static final enum hrtestColor RED;
public static final enum hrtestColor BLUE;
public static final enum hrtestColor BLACK;
public static final enum hrtestColor YELLOW;
public static final enum hrtestColor GREEN;
private static final synthetic hrtestColor〔〕 ENUM$VALUES;
// 初始化过程,对枚举类的所有枚举值对象进行第一次初始化
static {
0 new hrtestColor 〔1〕
3 dup
4 ldc 〔16〕 //把枚举值字符串“RED”压入 *** 作数栈
6 iconst_0 // 把整型值0压入 *** 作数栈
7 invokespecial hrtestColor(javalangString, int) 〔17〕 //调用Color类的私有构造器创建Color对象RED
10 putstatic hrtestColorRED : hrtestColor 〔21〕 //将枚举对象赋给Color的静态常量RED 。
。 。 。 枚举对象BLUE等与上同
102 return
};
// 私有构造器,外部不可能动态创建一个枚举类对象(也就是不可能动态创建一个枚举值) 。
private Color(javalangString arg0, int arg1){
// 调用父类Enum的受保护构造器创建一个枚举对象
3 invokespecial javalangEnum(javalangString, int) 〔38〕
};
public static hrtestColor〔〕 values();
// 实现Enum类的抽象方法
public static hrtestColor valueOf(javalangString arg0);
}
下面我们就详细介绍enum定义的枚举类的特征及其用法 。(后面均用Color举例)
1、Color枚举类就是class,而且是一个不可以被继承的final类 。
其枚举值(RED,BLUE 。)都是Color类型的类静态常量, 我们可以通过下面的方式来得到Color枚举类的一个实例:
Color c=ColorRED;
注意:这些枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写 。
2、即然枚举类是class,当然在枚举类型中有构造器,方法和数据域 。
但是,枚举类的构造器有很大的不同:
(1) 构造器只是在构造枚举值的时候被调用 。
Java代码:
enum Color{
RED(255,0,0),BLUE(0,0,255),BLACK(0,0,0),YELLOW(255,255,0),GREEN(0,255,0);
//构造枚举值,比如RED(255,0,0)
private Color(int rv,int gv,int bv){
thisredValue=rv;
thisgreenValue=gv;
thisblueValue=bv;
}
public String toString(){ //覆盖了父类Enum的toString()
return supertoString()+“(”+redValue+“,”+greenValue+“,”+blueValue+“)”;
}
private int redValue; //自定义数据域,private为了封装 。
private int greenValue;
private int blueValue;
}
(2) 构造器只能私有private,绝对不允许有public构造器 。 这样可以保证外部代码无法新构造枚举类的实例 。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已 。 但枚举类的方法和数据域可以允许外部访问 。
Java代码:
public static void main(String args〔〕)
{
// Color colors=new Color(100,200,300); //wrong
Color color=ColorRED;
Systemoutprintln(color); // 调用了toString()方法
}
3、所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法 。
(1) ordinal()方法: 返回枚举值在枚举类种的顺序 。这个顺序根据枚举值声明的顺序而定 。
ColorREDordinal(); //返回结果:0
ColorBLUEordinal(); //返回结果:1
(2) compareTo()方法: Enum实现了javalangComparable接口,因此可以比较象与指定对象的顺序 。Enum中的compareTo返回的是两个枚举值的顺序之差 。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常 。(具体可见源代码)
ColorREDcompareTo(ColorBLUE); //返回结果 -1
(3) values()方法: 静态方法,返回一个包含全部枚举值的数组 。
Color〔〕 colors=Colorvalues();
for(Color c:colors){
Systemoutprint(c+“,”);
}//返回结果:RED,BLUE,BLACK YELLOW,GREEN,
(4) toString()方法: 返回枚举常量的名称 。
Color c=ColorRED;
Systemoutprintln(c);//返回结果: RED
(5) valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量 。
ColorvalueOf(“BLUE”); //返回结果: ColorBLUE
(6) equals()方法: 比较两个枚举类对象的引用 。
Java代码:
//JDK源代码:
public final boolean equals(Object other) {
return this==other;
}
4、枚举类可以在switch语句中使用 。
Java代码:
Color color=ColorRED;
switch(color){
case RED: Systemoutprintln(“it‘s red”);break;
case BLUE: Systemoutprintln(“it’s blue”);break;
case BLACK: Systemoutprintln(“it‘s blue”);break;
}
以上就是关于枚举类型的用法全部的内容,包括:枚举类型的用法、Swift 枚举(enum)详解、JavaScript属性可枚举性谁能给我解释下什么叫做属性的可枚举性,谢谢了等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)