Tôi không nghĩ rằng về cơ bản tôi hiểu thế nào là một cái gì enum
và khi nào nên sử dụng nó.
Ví dụ:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Điều gì thực sự được tuyên bố ở đây?
Tôi không nghĩ rằng về cơ bản tôi hiểu thế nào là một cái gì enum
và khi nào nên sử dụng nó.
Ví dụ:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Điều gì thực sự được tuyên bố ở đây?
Câu trả lời:
Ba điều đang được tuyên bố ở đây: một kiểu liệt kê vô danh được khai báo, ShapeType
đã được tuyên bố một typedef cho rằng liệt kê vô danh, và ba tên kCircle
, kRectangle
và kOblateSpheroid
đang được khai báo là hằng số không thể thiếu.
Hãy phá vỡ nó. Trong trường hợp đơn giản nhất, một bảng liệt kê có thể được khai báo là
enum tagname { ... };
Điều này tuyên bố một bảng liệt kê với thẻ tagname
. Trong C và Objective-C (nhưng không phải C ++), bất kỳ tài liệu tham khảo nào về điều này phải được đi trước với enum
từ khóa. Ví dụ:
enum tagname x; // declare x of type 'enum tagname'
tagname x; // ERROR in C/Objective-C, OK in C++
Để tránh phải sử dụng enum
từ khóa ở mọi nơi, một typedef có thể được tạo:
enum tagname { ... };
typedef enum tagname tagname; // declare 'tagname' as a typedef for 'enum tagname'
Điều này có thể được đơn giản hóa thành một dòng:
typedef enum tagname { ... } tagname; // declare both 'enum tagname' and 'tagname'
Và cuối cùng, nếu chúng ta không cần để có thể sử dụng enum tagname
với enum
từ khóa, chúng tôi có thể làm cho enum
vô danh và chỉ khai báo nó với tên typedef:
typedef enum { ... } tagname;
Bây giờ, trong trường hợp này, chúng tôi tuyên bố ShapeType
là một tên được đánh máy của một bảng liệt kê ẩn danh. ShapeType
thực sự chỉ là một loại không thể thiếu, và chỉ nên được sử dụng để khai báo các biến mà giữ một trong các giá trị được liệt kê trong phần khai báo (có nghĩa là, một trong những kCircle
, kRectangle
và kOblateSpheroid
). Tuy nhiên, bạn có thể gán một ShapeType
biến khác một giá trị bằng cách truyền, vì vậy bạn phải cẩn thận khi đọc các giá trị enum.
Cuối cùng, kCircle
, kRectangle
, và kOblateSpheroid
được khai báo là hằng số không thể thiếu trong không gian tên toàn cầu. Vì không có giá trị cụ thể nào được chỉ định, chúng được gán cho các số nguyên liên tiếp bắt đầu bằng 0, do đó kCircle
là 0, kRectangle
là 1 và kOblateSpheroid
là 2.
Apple khuyên bạn nên xác định enums như thế này kể từ Xcode 4.4 :
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Họ cũng cung cấp một macro tiện dụng NS_ENUM
:
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
Các định nghĩa này cung cấp kiểm tra loại mạnh hơn và hoàn thành mã tốt hơn. Tôi không thể tìm thấy tài liệu chính thức về NS_ENUM
, nhưng bạn có thể xem video "Modern Objective-C" từ phiên WWDC 2012 tại đây .
CẬP NHẬT
Liên kết đến tài liệu chính thức ở đây .
NS_ENUM
macro của Apple bởi NSHipster: NSHipster.com/ns_enum-ns_options
Cập nhật thay đổi 64 bit: Theo tài liệu của apple về các thay đổi 64 bit,
Số liệt kê cũng được gõ: Trong trình biên dịch LLVM, các kiểu liệt kê có thể xác định kích thước của bảng liệt kê. Điều này có nghĩa là một số loại liệt kê cũng có thể có kích thước lớn hơn bạn mong đợi. Giải pháp, như trong tất cả các trường hợp khác, là không đưa ra giả định nào về kích thước của loại dữ liệu. Thay vào đó, gán bất kỳ giá trị liệt kê nào cho một biến có kiểu dữ liệu phù hợp
Vì vậy, bạn phải tạo enum với kiểu cú pháp dưới đây nếu bạn hỗ trợ 64-bit.
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
hoặc là
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Nếu không, nó sẽ dẫn đến cảnh báo như Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType
Cập nhật cho lập trình nhanh chóng:
Trong swift, có một sự thay đổi cú pháp.
enum ControlButtonID: NSUInteger {
case kCircle , kRectangle, kOblateSpheroid
}
Enum (viết tắt của phép liệt kê) được sử dụng để liệt kê một tập hợp các giá trị (liệt kê). Giá trị là một thứ trừu tượng được biểu thị bằng một ký hiệu (một từ). Ví dụ, một enum cơ bản có thể là
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };
Enum này được gọi là ẩn danh vì bạn không có ký hiệu để đặt tên cho nó. Nhưng nó vẫn hoàn toàn chính xác. Chỉ cần sử dụng nó như thế này
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
Đồng ý. Cuộc sống thật đẹp và mọi thứ đều suôn sẻ. Nhưng một ngày nào đó bạn cần sử dụng lại enum này để xác định một biến mới để lưu trữ myGrandFatherPantSize, sau đó bạn viết:
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;
Nhưng sau đó, bạn có một lỗi biên dịch "xác định lại của điều tra viên". Trên thực tế, vấn đề là trình biên dịch không chắc chắn rằng bạn là enum đầu tiên và bạn là người thứ hai mô tả điều tương tự.
Sau đó, nếu bạn muốn sử dụng lại cùng một bộ liệt kê (ở đây xs ... xxxxl) ở một số nơi, bạn phải gắn thẻ nó với một tên duy nhất. Lần thứ hai bạn sử dụng bộ này, bạn chỉ cần sử dụng thẻ. Nhưng đừng quên rằng thẻ này không thay thế từ enum mà chỉ là bộ liệt kê. Sau đó hãy cẩn thận để sử dụng enum như bình thường. Như thế này:
// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
// here the second use of my enum. It works now!
enum sizes myGrandFatherPantSize;
bạn cũng có thể sử dụng nó trong một định nghĩa tham số:
// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;
Bạn có thể nói rằng viết lại enum ở mọi nơi không thuận tiện và làm cho mã trông hơi lạ. Bạn đúng rồi. Một loại thực sự sẽ tốt hơn.
Đây là bước cuối cùng của sự tiến bộ vĩ đại của chúng tôi đến hội nghị thượng đỉnh. Chỉ cần thêm một typedef, hãy biến enum của chúng ta thành một kiểu thực. Ồ, điều cuối cùng, typedef không được phép trong lớp của bạn. Sau đó xác định loại của bạn ở trên. Làm như thế này:
// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type
@interface myClass {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
Hãy nhớ rằng thẻ là tùy chọn. Sau đó, trong trường hợp đó, chúng tôi không gắn thẻ cho các điều tra viên mà chỉ để xác định một loại mới. Sau đó, chúng tôi không thực sự cần nó nữa.
// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;
@interface myClass : NSObject {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
@end
Nếu bạn đang phát triển trong Objective-C với XCode, tôi sẽ cho phép bạn khám phá một số macro đẹp có tiền tố NS_ENUM. Điều đó sẽ giúp bạn xác định các enum tốt một cách dễ dàng và hơn nữa sẽ giúp bộ phân tích tĩnh thực hiện một số kiểm tra thú vị cho bạn trước khi biên dịch.
Tốt Enum!
typedef
rất hữu ích để xác định lại tên của một loại biến hiện có. Nó cung cấp cách ngắn gọn và có ý nghĩa để gọi một kiểu dữ liệu. ví dụ:
typedef unsigned long int TWOWORDS;
ở đây, kiểu int unsign dài được xác định lại là kiểu TWOWORDS. Vì vậy, bây giờ chúng ta có thể khai báo các biến kiểu không dấu int dài bằng cách viết,
TWOWORDS var1, var2;
thay vì
unsigned long int var1, var2;
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
sau đó bạn có thể sử dụng nó như: -
ShapeType shape;
và
enum {
kCircle,
kRectangle,
kOblateSpheroid
}
ShapeType;
bây giờ bạn có thể sử dụng nó như: -
enum ShapeType shape;
enum được sử dụng để gán giá trị cho các phần tử enum không thể thực hiện được trong struct. Vì vậy, mọi lúc thay vì truy cập vào biến hoàn chỉnh, chúng ta có thể thực hiện nó bằng giá trị chúng ta gán cho các biến trong enum. Theo mặc định, nó bắt đầu bằng phép gán 0 nhưng chúng ta có thể gán cho nó bất kỳ giá trị nào và biến tiếp theo trong enum sẽ được gán một giá trị giá trị +1 trước đó.
Bạn có thể sử dụng ở định dạng bên dưới, Giá trị mặc định thô bắt đầu từ 0, vì vậy
Bạn có thể chỉ định giá trị bắt đầu cụ thể của riêng bạn.
typedef enum : NSUInteger {
kCircle, // for your value; kCircle = 5, ...
kRectangle,
kOblateSpheroid
} ShapeType;
ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0
Một typedef cho phép lập trình viên xác định một loại Objective-C là một loại khác. Ví dụ,
typedef int Counter; định nghĩa kiểu Counter tương đương với kiểu int. Điều này cải thiện đáng kể khả năng đọc mã.
Typedef là một từ khóa trong C và C ++. Nó được sử dụng để tạo tên mới cho các kiểu dữ liệu cơ bản (char, int, float, double, struct & enum) .
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Ở đây, nó tạo ra kiểu dữ liệu liệt kê ShapeType & chúng ta có thể viết tên mới cho kiểu enum ShapeType như được đưa ra dưới đây
ShapeType shape1;
ShapeType shape2;
ShapeType shape3;
enum có thể giảm nhiều loại "lỗi" và làm cho mã dễ quản lý hơn
#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER
Định nghĩa không có ràng buộc. Nó chỉ đơn giản là một sự thay thế. Nó không thể giới hạn tất cả các điều kiện của nhà nước. Khi STATE được gán cho 5, chương trình sẽ sai, vì không có trạng thái khớp. Nhưng trình biên dịch sẽ không cảnh báo STATE = 5
Vì vậy, tốt hơn là sử dụng như thế này
typedef enum SampleState {
SampleStateGood = 0,
SampleStateBad,
SampleStateOther
} SampleState;
SampleState state = SampleStateGood;