Enum class เป็นข้อมูลที่ผู้ใช้งานกำหนดชื่อของลำดับตัวเลขขึ้นมา แทนที่จะใช้ String ตรง ๆ มันมีประสิทธิภาพและช่วยให้โปรแกรมอ่านง่ายขึ้น ข้อมูล enums เป็นที่นิยมใช้งานกันในหลายภาษาโปรแกรม
การใช้งานหลัก ๆ ของ enum เป็นการกำหนด choices สำหรับเลือกสิ่งที่ต้องการจากคำตอบจากสมาชิกทั้งหมด แล้วส่งผ่าน parameter ในฟังก์ชั่นเพื่อสื่อสารกันในโปรแกรม
ทำเหมือนการประกาศ class แต่ตัว enum จะมีเฉพาะการประกาศชื่อที่จะใช้แทน index แต่ละตัวเท่านั้น ในการใช้งานตัว enum เป็นเหมือน static variable แบบหนึ่ง สามารถอ้างถึงด้วยชื่อของ enum ได้เลย
การตั้งชื่อสมาชิกใน enum จะใช้หลักการเดียวกับการตั้งชื่อตัวแปรแบบ lowerCamelCase
enum MyColor { red, green, blue }
void main() {
print(MyColor.red); // output → MyColor.red
print(MyColor.red.index); // output → 0
print(MyColor.green); // output → MyColor.green
print(MyColor.green.index); // output → 1
print(MyColor.blue); // output → MyColor.blue
print(MyColor.blue.index); // output → 2
}
การใช้งาน Enum จะมองว่าตัวสมาชิกที่กำหนดขึ้นมาใช้อ้างอิงและเปรียบเทียบกันได้
enum MyColor { red, green, blue }
void main() {
var color1 = MyColor.red;
switch (color1) {
case MyColor.red:
print('color1 is red');
case MyColor.green:
print('color1 is green');
case MyColor.blue:
print('color1 is blue');
default:
}
}
ผลที่ได้
color1 is red
ในตัว enum ยังมีคำสั่งต่าง ๆ ที่มีประโยชน์ในการเข้าถึงและใช้งานสมาชิกแต่ละตัวได้
สมาชิกของ enum สามารถใช้คำสั่ง .values
เพื่อเข้าถึง List ของสมาชิกทั้งหมดของ enum ได้เลย
enum MyColor { red, green, blue }
void main() {
List<MyColor> colorList = MyColor.values;
print(colorList.length); // output → 3
colorList.forEach(print); // output →
// MyColor.red
// MyColor.green
// MyColor.blue
MyColor color1 = colorList.first;
print(color1); // output → MyColor.red
print(color1.index); // output → 0
print(color1.name); // output → red
print(color1.name.toUpperCase()); // output → RED
}
ทุกสมาชิกของ enum จะมีเลข index ที่ไม่ซ้ำกัน เริ่มต้นที่ 0 สามารถอ่านค่าดังกล่าวด้วยคำสั่ง .index
จะได้ค่า int
กลับมา
enum MyColor { red, green, blue }
void main() {
print(MyColor.red.index); // output → 0
print(MyColor.green.index); // output → 1
print(MyColor.blue.index); // output → 2
}
ทุกสมาชิกของ enum จะมีคำสั่ง .name
ที่คืนค่าเป็น String
ชื่อของสมาชิกเอง
enum MyColor { red, green, blue }
void main() {
MyColor color1 = MyColor.red;
print(color1); // output → MyColor.red
print(color1.name); // output → red
print(color1.name.toUpperCase()); // output → RED
print("color1 is ${color1.name}"); // output → color1 is red
}
การเปรียบเทียบสมาชิก enum ด้วย static method สามารถทำได้ 2 แบบ คือ
Enum.compareByIndex
Enum.compareByName
Enum.compareByIndex
จะเป็นการเปรียบเทียบสมาชิกของ enum โดยการเอาค่า index มาลบกัน คืนผลต่างที่ได้
enum MyColor { red, green, blue }
void main() {
MyColor colorRed = MyColor.red;
MyColor colorBlue = MyColor.blue;
print(colorRed.index - colorBlue.index); // output → -2
print(colorRed.index > colorBlue.index); // output → false
print(Enum.compareByIndex(colorRed, colorBlue)); // output → -2
}
จากตัวอย่าง ผู้ใช้สามารถเลือกได้ว่าจะเอา index มาลบกันด้วยตัวเอง หรือทำผ่าน Enum.compareByIndex
ซึ่งมีผลในการทำความเข้าใจว่าโปรแกรมกำลังทำอะไร
Enum.compareByName
จะเปรียบเทียบสมาชิกตามชื่อแทน โดยจะเปรียบเทียบแบบ case sensitive การทำงานไม่ต่างจาก String.compareTo()
enum MyColor { red, green, blue }
void main() {
MyColor colorRed = MyColor.red;
MyColor colorBlue = MyColor.blue;
print(Enum.compareByName(colorRed, colorBlue)); // output → 1
print(colorRed.name.compareTo(colorBlue.name)); // output → 1
}
ประโยชน์อีกข้อคือ หากต้องการสร้าง List ของสมาชิก enum ที่ให้เรียงตามชื่อ name แทน สามารถใช้ .sort()
เพื่อการเรียงลำดับได้
enum MyColor { red, green, blue }
void main() {
List<MyColor> colors = [...MyColor.values];
print(colors); // output → [MyColor.red, MyColor.green, MyColor.blue]
// sort by name of enum member
colors.sort(Enum.compareByName);
print(colors); // output → [MyColor.blue, MyColor.green, MyColor.red]
// use .. operator when create list
List<MyColor> colorAtoZ = [...MyColor.values]..sort(Enum.compareByName);
print(colorAtoZ); // output → [MyColor.blue, MyColor.green, MyColor.red]
}
ตัว Enum จะเก็บลำดับสมาชิกเป็น index ค่าเริ่มต้นที่ 0 หากต้องการใช้ค่า index เพื่อดึงค่าสมาชิกกลับมา สามารถทำได้โดยผ่าน .values[index]
enum SimpleAnimal { cat, bat, rat }
void main() {
print(SimpleAnimal.values.length); // output → 3
print(SimpleAnimal.values[0]); // output → SimpleAnimal.cat
print(SimpleAnimal.values[1]); // output → SimpleAnimal.bat
print(SimpleAnimal.values[2]); // output → SimpleAnimal.rat
print(SimpleAnimal.values[3]); // RangeError (index): Invalid value: Not in inclusive range 0..2: 3
}
เนื่องจากตัว Enum มีการเก็บชื่อของสมาชิกเป็น String เอาไว้ด้วย ดังนั้นจึงเป็นเรื่องไม่อยากที่จะเอาข้อความ String มาแปลงกลับเป็น Enum
enum SimpleAnimal { cat, bat, rat }
void main() {
String myRat = "rat";
try {
SimpleAnimal result = SimpleAnimal.values.firstWhere((element) => element.name.compareTo(myRat) == 0);
print(result); // output → SimpleAnimal.rat
} catch (e) {
print('Can not conver "$myRat" to SimpleAnimal'); // no output
}
String myAnt = "ant";
try {
SimpleAnimal result = SimpleAnimal.values.firstWhere((element) => element.name.compareTo(myAnt) == 0);
print(result); // no output
} catch (e) {
print('Can not conver "$myAnt" to SimpleAnimal'); // → Can not conver "ant" to SimpleAnimal
}
}
ผลที่ได้
SimpleAnimal.rat
Can not conver "ant" to SimpleAnimal
ในตัวอย่าง จะเป็นการเปรียบเทียบค่าใน List ของ Enum ว่ามีสมาชิกตัวไหนที่ .name
มีค่าเท่ากับ String ที่สนใจ โดยผ่านคำสั่ง .firstWhere()
หากไม่พบสมาชิกที่ตรงกับใน enum ก็จะแสดงข้อความแจ้งให้ทราบ
ใน Dart ตั้งแต่ 2.17 ขึ้นไป จะสามารถสร้าง enhanced enumsได้ วิธีการสร้างก็คล้าย ๆ กับการประกาศ class แต่มีจุดที่ไม่เหมือนกันคือ Instance ที่ได้จากการสร้างจะเป็น final และ ตัว constructor ต้องเป็น constant ส่วนรายละเอียดอื่น ๆ อ่านได้จาก Declaring enhanced enum
ตัวอย่างสร้าง MyColor ที่เป็น enum เพื่อเก็บค่าสี RGB
enum MyColor {
red(r: 255, g: 0, b: 0),
green(r: 0, g: 255, b: 0),
blue(r: 0, g: 0, b: 255);
final int r, g, b;
const MyColor({required this.r, required this.g, required this.b});
}
void main() {
var blueColor = MyColor.blue;
print(blueColor); // output → MyColor.blue
print(blueColor.r); // output → 0
print(blueColor.g); // output → 0
print(blueColor.b); // output → 255
print(MyColor.red.r); // output → 255
print(MyColor.red.g); // output → 0
print(MyColor.red.b); // output → 0
print(MyColor.green.r); // output → 0
print(MyColor.green.g); // output → 255
print(MyColor.green.b); // output → 0
}
จากตัวอย่าง ใน enum ประกาศ MyColor()
constructor มีสมาชิกเป็น r
g
b
เมื่อเรียกคำสั่ง MyColor.blue
ก็จะเหมือนไปเรียก MyColor(r: 0, g: 0, b: 255)
เนื่องจากมันทำงานคล้ายกับการประกาศ class มันจึงสามารถ implement และใส่ method เข้าไปได้ด้วย มาลองใส่การแปลงค่าสี RGB เป็น Web Color กันดู
enum MyColor {
red(r: 255, g: 0, b: 0),
green(r: 0, g: 255, b: 0),
blue(r: 0, g: 0, b: 255);
final int r, g, b;
const MyColor({required this.r, required this.g, required this.b});
String get webColorCode {
String rHex = r.toRadixString(16).padLeft(2, '0');
String gHex = g.toRadixString(16).padLeft(2, '0');
String bHex = b.toRadixString(16).padLeft(2, '0');
return "#$rHex$gHex$bHex";
}
}
void main() {
var blueColor = MyColor.blue;
print(blueColor.webColorCode); // output → #0000ff
print(MyColor.blue.webColorCode); // output → #0000ff
print(MyColor.red.webColorCode); // output → #ff0000
}
ลอง implement ด้วย Comparable<T>
เพื่อให้สามารถใช้คำสั่ง compareTo()
ได้ ในการเปรียบเทียบจะใช้วิธีแปลงค่า RGB เป็นเลขจำนวนเต็ม แล้วค่าผลลัพธ์ที่ได้ของทั้ง 2 ตัว เอามาลบกัน
enum MyColor implements Comparable<MyColor> {
red(r: 255, g: 0, b: 0),
green(r: 0, g: 255, b: 0),
blue(r: 0, g: 0, b: 255);
final int r, g, b;
const MyColor({required this.r, required this.g, required this.b});
@override
int compareTo(MyColor other) {
int colorThis = (r * 65536) + (g * 256) + b;
int colorOther = (other.r * 65536) + (other.g * 256) + other.b;
return colorThis - colorOther;
}
}
void main() {
var blueColor = MyColor.blue;
var redColor = MyColor.red;
print(redColor.compareTo(blueColor)); // output → 16711425
print(redColor.compareTo(MyColor.red)); // output → 0
// sort MyColor list
List<MyColor> colors = [MyColor.green, MyColor.red, MyColor.blue];
colors.sort();
print(colors); // output → [MyColor.blue, MyColor.green, MyColor.red]
}