Nie sądzę, że zasadniczo rozumiem, co to enum
jest i kiedy go używać.
Na przykład:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Co tak naprawdę deklaruje się tutaj?
Nie sądzę, że zasadniczo rozumiem, co to enum
jest i kiedy go używać.
Na przykład:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Co tak naprawdę deklaruje się tutaj?
Odpowiedzi:
Trzy rzeczy są deklarowane są tutaj: anonimowy typ wyliczeniowy jest deklarowana, ShapeType
jest ogłoszony typedef dla tego anonimowe wyliczanie, a trzy nazwy kCircle
, kRectangle
i kOblateSpheroid
zostały zadeklarowane jako integralne stałych.
Rozwalmy to. W najprostszym przypadku wyliczenie można zadeklarować jako
enum tagname { ... };
To deklaruje wyliczenie ze znacznikiem tagname
. W C i Objective-C (ale nie w C ++) wszelkie odniesienia do tego muszą być poprzedzone enum
słowem kluczowym. Na przykład:
enum tagname x; // declare x of type 'enum tagname'
tagname x; // ERROR in C/Objective-C, OK in C++
Aby uniknąć konieczności używania enum
słowa kluczowego w dowolnym miejscu, można utworzyć typedef:
enum tagname { ... };
typedef enum tagname tagname; // declare 'tagname' as a typedef for 'enum tagname'
Można to uprościć w jednym wierszu:
typedef enum tagname { ... } tagname; // declare both 'enum tagname' and 'tagname'
I wreszcie, jeśli nie potrzebujemy, aby móc korzystać enum tagname
z enum
hasła, możemy dokonać enum
anonimowy i tylko zadeklarować ją z nazwą typedef:
typedef enum { ... } tagname;
Teraz w tym przypadku deklarujemy, że jesteśmy ShapeType
anonimowym wyliczeniem na maszynie. ShapeType
jest naprawdę tylko integralną typu i powinny być wykorzystywane jedynie zadeklarować zmienne, które posiadają jedną z wartości wymienionych w deklaracji (czyli jeden kCircle
, kRectangle
i kOblateSpheroid
). Możesz jednak przypisać ShapeType
zmienną inną wartość poprzez rzutowanie, więc musisz zachować ostrożność podczas odczytywania wartości wyliczeniowych.
Wreszcie kCircle
, kRectangle
i kOblateSpheroid
zostały zadeklarowane jako integralne stałe w globalnej przestrzeni nazw. Ponieważ nie określono żadnych konkretnych wartości, są one przypisywane do kolejnych liczb całkowitych rozpoczynających się od 0, więc kCircle
wynosi 0, kRectangle
wynosi 1 i kOblateSpheroid
wynosi 2.
Apple zaleca zdefiniowanie takich wyliczeń od Xcode 4.4 :
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Zapewniają również przydatne makro NS_ENUM
:
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
Te definicje zapewniają silniejsze sprawdzanie typów i lepsze uzupełnianie kodu. Nie mogłem znaleźć oficjalnej dokumentacji NS_ENUM
, ale możesz obejrzeć film „Modern Objective-C” z sesji WWDC 2012 tutaj .
AKTUALIZACJA
Link do oficjalnej dokumentacji tutaj .
NS_ENUM
makra Apple'a przez NSHipster: NSHipster.com/ns_enum-ns_options
Użytkownik definiuje typ, który ma możliwych wartości kCircle
, kRectangle
lub kOblateSpheroid
. Jednak wartości w wyliczeniu (kCircle itp.) Są widoczne poza wyliczeniem. Ważne jest, aby o tym pamiętać ( int i = kCircle;
na przykład obowiązuje).
Aktualizacja dotycząca zmiany 64-bitowej: Według dokumentów Apple na temat zmian 64-bitowych,
Wyliczane są również typy: W kompilatorze LLVM typy wyliczone mogą określać rozmiar wyliczenia. Oznacza to, że niektóre wyliczone typy mogą mieć również rozmiar większy niż się spodziewasz. Rozwiązaniem, podobnie jak we wszystkich innych przypadkach, jest brak jakichkolwiek założeń dotyczących wielkości typu danych. Zamiast tego przypisz dowolne wyliczone wartości do zmiennej o odpowiednim typie danych
Więc musisz utworzyć wyliczenie z typem jak poniżej składni, jeśli obsługujesz 64-bit.
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
lub
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
W przeciwnym razie doprowadzi to do ostrzeżenia jako Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType
Aktualizacja do szybkiego programowania:
W krótkim czasie następuje zmiana składni.
enum ControlButtonID: NSUInteger {
case kCircle , kRectangle, kOblateSpheroid
}
Wyliczenie (skrót wyliczenia) służy do wyliczenia zestawu wartości (podmiotów wyliczających). Wartość jest abstrakcyjną rzeczą reprezentowaną przez symbol (słowo). Na przykład podstawowym wyliczeniem może być
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };
Ten wylicznik nazywa się anonimowy, ponieważ nie masz symbolu, który mógłby go nazwać. Ale nadal jest całkowicie poprawne. Po prostu użyj tego w ten sposób
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
Ok. Życie jest piękne i wszystko idzie dobrze. Ale pewnego dnia musisz ponownie użyć tego wyliczenia, aby zdefiniować nową zmienną do przechowywania myGrandFatherPantSize, a następnie piszesz:
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;
Ale wtedy pojawia się błąd kompilatora „redefinicja modułu wyliczającego”. W rzeczywistości problem polega na tym, że kompilator nie jest pewien, że najpierw wyliczysz, a ty drugi to samo.
Następnie, jeśli chcesz ponownie użyć tego samego zestawu modułów wyliczających (tutaj xs ... xxxxl) w kilku miejscach, musisz oznaczyć go unikalną nazwą. Przy drugim użyciu tego zestawu wystarczy użyć tagu. Ale nie zapominaj, że ten znacznik nie zastępuje słowa wyliczeniowego, a jedynie zestaw jednostek wyliczających. Następnie, jak zwykle, używaj enum. Lubię to:
// 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;
możesz go również użyć w definicji parametru:
// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;
Można powiedzieć, że przepisywanie enum wszędzie nie jest wygodne i sprawia, że kod wygląda trochę dziwnie. Masz rację. Prawdziwy typ byłby lepszy.
To ostatni krok naszego wielkiego postępu na szczyt. Po prostu dodając typedef przekształćmy nasze wyliczenie w prawdziwy typ. Aha, ostatnia rzecz, typedef nie jest dozwolony w twojej klasie. Następnie określ swój typ tuż powyżej. Zrób to tak:
// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type
@interface myClass {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
Pamiętaj, że tag jest opcjonalny. Następnie, ponieważ tutaj, w tym przypadku, nie tagujemy modułów wyliczających, a jedynie definiujemy nowy typ. Więc tak naprawdę nie potrzebujemy już tego.
// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;
@interface myClass : NSObject {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
@end
Jeśli rozwijasz się w Objective-C z XCode, pozwolę ci odkryć kilka fajnych makr z prefiksem NS_ENUM. Powinno to pomóc w łatwym zdefiniowaniu dobrych wyliczeń, a ponadto pomoże statycznemu analizatorowi wykonać kilka interesujących kontroli przed kompilacją.
Dobry Enum!
typedef
jest przydatny do przedefiniowania nazwy istniejącego typu zmiennej. Zapewnia krótki i znaczący sposób na wywołanie typu danych. na przykład:
typedef unsigned long int TWOWORDS;
tutaj typ bez znaku long int jest redefiniowany na typ TWOWORDS. Dlatego możemy teraz deklarować zmienne typu unsigned long int, pisząc,
TWOWORDS var1, var2;
zamiast
unsigned long int var1, var2;
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
możesz użyć go w następujący sposób:
ShapeType shape;
i
enum {
kCircle,
kRectangle,
kOblateSpheroid
}
ShapeType;
teraz możesz używać go w następujący sposób:
enum ShapeType shape;
enum służy do przypisywania wartości elementom wyliczającym, których nie można wykonać w strukturze. Dlatego za każdym razem zamiast uzyskiwać dostęp do pełnej zmiennej, możemy to zrobić według wartości, którą przypisujemy zmiennym w wyliczeniu. Domyślnie zaczyna się od przypisania 0, ale możemy przypisać mu dowolną wartość, a następnej zmiennej w enum zostanie przypisana wartość poprzedniej wartości +1.
Możesz użyć w poniższym formacie surowej wartości domyślnej od 0, więc
Możesz przypisać własną określoną wartość początkową.
typedef enum : NSUInteger {
kCircle, // for your value; kCircle = 5, ...
kRectangle,
kOblateSpheroid
} ShapeType;
ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0
Typedef pozwala programiście zdefiniować jeden typ Objective-C jako inny. Na przykład,
typedef int Counter; definiuje typ Licznik jako równoważny typowi int. To drastycznie poprawia czytelność kodu.
Typedef jest słowem kluczowym w językach C i C ++. Służy do tworzenia nowych nazw dla podstawowych typów danych (char, int, float, double, struct & enum) .
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Tutaj tworzy wyliczony typ danych ShapeType i możemy pisać nowe nazwy dla typu wyliczeniowego ShapeType, jak podano poniżej
ShapeType shape1;
ShapeType shape2;
ShapeType shape3;
Wyliczanie może zmniejszyć wiele rodzajów „błędów” i sprawić, że kod będzie łatwiejszy do zarządzania
#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER
Definicja nie ma ograniczeń. To po prostu zmiana. Nie jest w stanie ograniczyć wszystkich warunków państwa. Kiedy STATE jest przypisane do 5, program będzie błędny, ponieważ nie ma pasującego stanu. Ale kompilator nie ostrzeże STATE = 5
Dlatego lepiej jest używać w ten sposób
typedef enum SampleState {
SampleStateGood = 0,
SampleStateBad,
SampleStateOther
} SampleState;
SampleState state = SampleStateGood;