The Dart Language: เมื่อ Java และ C# ยังไม่คมชัดเพียงพอ
เผยแพร่แล้ว: 2022-03-11ย้อนกลับไปในปี 2013 การเปิดตัวเวอร์ชัน 1.0 อย่างเป็นทางการของ Dart ได้รับการเผยแพร่ เช่นเดียวกับข้อเสนอของ Google ส่วนใหญ่ แต่ไม่ใช่ทุกคนที่กระตือรือร้นเท่าทีมภายในของ Google ในการสร้างแอปที่มีความสำคัญต่อธุรกิจด้วยภาษา Dart ด้วยการสร้างใหม่ของ Dart 2 ที่รอบคอบในห้าปีต่อมา Google ดูเหมือนจะพิสูจน์ให้เห็นถึงความมุ่งมั่นในด้านภาษา อันที่จริง ทุกวันนี้ นักพัฒนายังคงได้รับแรงฉุดลากอย่างต่อเนื่อง โดยเฉพาะ Java และ C#
ภาษาโปรแกรม Dart มีความสำคัญด้วยเหตุผลบางประการ:
- มีสิ่งที่ดีที่สุดของทั้งสองโลก: เป็นภาษาที่คอมไพล์แล้ว ปลอดภัยสำหรับการพิมพ์ (เช่น C# และ Java) และภาษาสคริปต์ (เช่น Python และ JavaScript) ในเวลาเดียวกัน
- มันแปลงเป็น JavaScript เพื่อใช้เป็นส่วนหน้าของเว็บ
- มันทำงานบนทุกสิ่ง และคอมไพล์ไปยังแอพมือถือที่มาพร้อมเครื่อง คุณจึงสามารถใช้งานได้เกือบทุกอย่าง
- Dart นั้นคล้ายกับ C# และ Java ในไวยากรณ์ ดังนั้นจึงเรียนรู้ได้อย่างรวดเร็ว
พวกเราจากโลก C# หรือ Java ของระบบองค์กรขนาดใหญ่รู้อยู่แล้วว่าทำไมความปลอดภัยของประเภท ข้อผิดพลาดในการคอมไพล์ และ Linters จึงมีความสำคัญ พวกเราหลายคนลังเลที่จะใช้ภาษา "สคริปต์" เพราะกลัวว่าจะสูญเสียโครงสร้าง ความเร็ว ความแม่นยำ และความสามารถในการแก้ไขข้อบกพร่องทั้งหมดที่เราคุ้นเคย
แต่ด้วยการพัฒนา Dart เราไม่ต้องละทิ้งสิ่งนั้น เราสามารถเขียนแอพมือถือ เว็บไคลเอนต์ และแบ็คเอนด์ในภาษาเดียวกัน—และรับทุกสิ่งที่เรายังคงชื่นชอบเกี่ยวกับ Java และ C#!
ในตอนท้าย เรามาดูตัวอย่างภาษา Dart ที่สำคัญซึ่งน่าจะใหม่สำหรับนักพัฒนา C# หรือ Java ซึ่งเราจะสรุปเป็น PDF ภาษา Dart ในตอนท้าย
หมายเหตุ: บทความนี้ครอบคลุมเฉพาะ Dart 2.x เวอร์ชัน 1.x ไม่ได้ "ปรุงเต็มที่" - โดยเฉพาะระบบประเภทเป็นคำแนะนำ (เช่น TypeScript) แทนที่จะเป็นที่จำเป็น (เช่น C# หรือ Java)
1. องค์กรรหัส
อันดับแรก เราจะพูดถึงความแตกต่างที่สำคัญที่สุดอย่างหนึ่ง นั่นคือ วิธีจัดระเบียบและอ้างอิงไฟล์โค้ด
ไฟล์ต้นฉบับ ขอบเขต เนมสเปซ และการนำเข้า
ใน C # คอลเล็กชันของคลาสจะถูกคอมไพล์ไปยังแอสเซมบลี แต่ละคลาสมีเนมสเปซ และบ่อยครั้งเนมสเปซสะท้อนถึงการจัดระเบียบของซอร์สโค้ดในระบบไฟล์—แต่ในท้ายที่สุด แอสเซมบลีจะไม่เก็บข้อมูลใดๆ เกี่ยวกับตำแหน่งไฟล์ซอร์สโค้ด
ใน Java ไฟล์ต้นฉบับเป็นส่วนหนึ่งของแพ็คเกจและเนมสเปซมักจะสอดคล้องกับตำแหน่งระบบไฟล์ แต่ในท้ายที่สุด แพ็คเกจเป็นเพียงคอลเล็กชันของคลาส
ดังนั้นทั้งสองภาษาจึงมีวิธีทำให้ซอร์สโค้ดไม่ขึ้นกับระบบไฟล์
ในทางตรงกันข้าม ในภาษา Dart ไฟล์ต้นฉบับแต่ละไฟล์จะต้องนำเข้าทุกอย่างที่อ้างถึง รวมถึงไฟล์ต้นทางอื่นๆ และแพ็คเกจของบริษัทอื่น ไม่มีเนมสเปซในลักษณะเดียวกัน และคุณมักจะอ้างถึงไฟล์ผ่านตำแหน่งระบบไฟล์ ตัวแปรและฟังก์ชันสามารถอยู่ในระดับบนสุด ไม่ใช่แค่คลาส ด้วยวิธีนี้ Dart จะเหมือนสคริปต์มากกว่า
ดังนั้น คุณจะต้องเปลี่ยนความคิดจาก "กลุ่มของชั้นเรียน" เป็น "ลำดับของไฟล์โค้ดที่รวมอยู่"
Dart รองรับทั้งการจัดแพ็คเกจและองค์กรเฉพาะกิจที่ไม่มีแพ็คเกจ เริ่มต้นด้วยตัวอย่างที่ไม่มีแพ็คเกจเพื่อแสดงลำดับของไฟล์ที่รวม:
// file1.dart int alice = 1; // top level variable int barry() => 2; // top level function var student = Charlie(); // top level variable; Charlie is declared below but that's OK class Charlie { ... } // top level class // alice = 2; // top level statement not allowed // file2.dart import 'file1.dart'; // causes all of file1 to be in scope main() { print(alice); // 1 }
ทุกสิ่งที่คุณอ้างถึงในไฟล์ต้นทางจะต้องมีการประกาศหรือนำเข้าภายในไฟล์นั้น เนื่องจากไม่มีระดับ "โครงการ" และไม่มีวิธีอื่นใดในการรวมองค์ประกอบต้นทางอื่นๆ ไว้ในขอบเขต
การใช้เนมสเปซเพียงอย่างเดียวใน Dart คือการตั้งชื่อให้กับการนำเข้า และนั่นจะส่งผลต่อวิธีที่คุณอ้างถึงรหัสที่นำเข้าจากไฟล์นั้น
// file2.dart import 'file1.dart' as wonderland; main() { print(wonderland.alice); // 1 }
แพ็คเกจ
ตัวอย่างด้านบนจัดระเบียบโค้ดโดยไม่มีแพ็คเกจ ในการใช้แพ็คเกจ โค้ดจะได้รับการจัดระเบียบอย่างเฉพาะเจาะจงมากขึ้น นี่คือตัวอย่างเค้าโครงแพ็คเกจสำหรับแพ็คเกจที่ชื่อ apples
:
-
apples/
-
pubspec.yaml
— กำหนดชื่อแพ็คเกจ การขึ้นต่อกัน และสิ่งอื่น ๆ -
lib/
-
apples.dart
นำเข้าและส่งออก; นี่คือไฟล์ที่นำเข้าโดยผู้บริโภคของแพ็คเกจ -
src/
-
seeds.dart
—โค้ดอื่นๆ ทั้งหมดที่นี่
-
-
-
bin/
-
runapples.dart
—มีฟังก์ชันหลักซึ่งเป็นจุดเริ่มต้น (หากเป็นแพ็คเกจที่รันได้หรือรวมเครื่องมือที่รันได้)
-
-
จากนั้นคุณสามารถนำเข้าทั้งแพ็คเกจแทนแต่ละไฟล์:
import 'package:apples';
แอปพลิเคชันที่ไม่สำคัญควรจัดเป็นแพ็คเกจเสมอ ซึ่งช่วยลดความจำเป็นที่ต้องทำซ้ำเส้นทางของระบบไฟล์ในแต่ละไฟล์ที่อ้างอิง แถมยังวิ่งเร็วขึ้นอีกด้วย นอกจากนี้ยังทำให้ง่ายต่อการแบ่งปันแพ็คเกจของคุณบน pub.dev ซึ่งนักพัฒนารายอื่นสามารถคว้ามันมาใช้งานเองได้อย่างง่ายดาย แพ็คเกจที่แอพของคุณใช้จะทำให้การคัดลอกซอร์สโค้ดไปยังระบบไฟล์ของคุณ ดังนั้นคุณจึงสามารถแก้ไขจุดบกพร่องในแพ็คเกจเหล่านั้นได้ลึกเท่าที่คุณต้องการ
2. ประเภทข้อมูล
มีความแตกต่างที่สำคัญในระบบประเภทของ Dart ที่ต้องระวัง เกี่ยวกับค่า Null ประเภทตัวเลข คอลเลกชั่น และประเภทไดนามิก
Nulls ทุกที่
มาจาก C # หรือ Java เราคุ้นเคยกับประเภท ดั้งเดิม หรือ ค่า ที่แตกต่างจากประเภท อ้างอิง หรือ วัตถุ ในทางปฏิบัติ ประเภทของค่าจะถูกจัดสรรบนสแต็กหรือในรีจิสเตอร์ และสำเนาของค่าจะถูกส่งเป็นพารามิเตอร์ของฟังก์ชัน ประเภทการอ้างอิงจะถูกจัดสรรบนฮีปแทน และส่งเฉพาะตัวชี้ไปยังอ็อบเจ็กต์เป็นพารามิเตอร์ของฟังก์ชัน เนื่องจากประเภทค่าจะใช้หน่วยความจำเสมอ ตัวแปรประเภทค่าจึงไม่สามารถเป็นค่าว่างได้ และสมาชิกประเภทค่าทั้งหมดต้องมีค่าเริ่มต้น
โผขจัดความแตกต่างนั้นเพราะทุกสิ่งเป็นวัตถุ ทุกประเภทได้มาจากประเภท Object
ในที่สุด ดังนั้น สิ่งนี้จึงถูกกฎหมาย:
int i = null;
อันที่จริง primitives ทั้งหมดถูกกำหนดโดยปริยายเป็น null
ซึ่งหมายความว่าคุณไม่สามารถสรุปได้ว่าค่าเริ่มต้นของจำนวนเต็มเป็นศูนย์ตามที่คุณคุ้นเคยใน C# หรือ Java และคุณอาจต้องเพิ่มการตรวจสอบค่าว่าง
ที่น่าสนใจคือแม้แต่ Null
ก็เป็นประเภทหนึ่ง และคำว่า null
หมายถึงอินสแตนซ์ของ Null
:
print(null.runtimeType); // prints Null
มีตัวเลขไม่มากนัก
ต่างจากการแบ่งประเภทจำนวนเต็มที่คุ้นเคยตั้งแต่ 8 ถึง 64 บิตที่มีการลงนามและไม่ได้ลงนาม ประเภทจำนวนเต็มหลักของ Dart เป็นเพียง int
ซึ่งเป็นค่า 64 บิต (นอกจากนี้ยังมี BigInt
สำหรับตัวเลขที่มีขนาดใหญ่มาก)
เนื่องจากไม่มีอาร์เรย์ไบต์เป็นส่วนหนึ่งของไวยากรณ์ภาษา เนื้อหาไฟล์ไบนารีจึงสามารถประมวลผลเป็นรายการของจำนวนเต็มได้ เช่น List<Int>
หากคุณกำลังคิดว่าสิ่งนี้จะต้องไม่มีประสิทธิภาพอย่างมาก นักออกแบบก็คิดไว้แล้ว ในทางปฏิบัติ มีการแทนค่าภายในที่แตกต่างกัน ขึ้นอยู่กับค่าจำนวนเต็มจริงที่ใช้ขณะรันไทม์ รันไทม์ไม่ได้จัดสรรหน่วยความจำฮีปสำหรับอ็อบเจ็กต์ int
ถ้ามันสามารถเพิ่มประสิทธิภาพนั้นออกไปและใช้การลงทะเบียน CPU ในโหมดที่ไม่ได้บรรจุในกล่อง นอกจากนี้ ไลบรารี byte_data
ยังเสนอ UInt8List
และการแสดงค่าอื่นๆ ที่ปรับให้เหมาะสมที่สุด
ของสะสม
คอลเลคชันและยาชื่อสามัญเป็นเหมือนสิ่งที่เราคุ้นเคย สิ่งสำคัญที่ควรทราบคือไม่มีอาร์เรย์ขนาดคงที่: เพียงใช้ประเภทข้อมูล List
ทุกที่ที่คุณจะใช้อาร์เรย์
นอกจากนี้ยังมีการสนับสนุน syntax สำหรับการเริ่มต้นคอลเลกชันสามประเภท:
final a = [1, 2, 3]; // inferred type is List<int>, an array-like ordered collection final b = {1, 2, 3}; // inferred type is Set<int>, an unordered collection final c = {'a': 1, 'b': 2}; // inferred type is Map<string, int>, an unordered collection of name-value pairs
ดังนั้น ใช้ Dart List
ที่คุณจะใช้ Java array, ArrayList
หรือ Vector
; หรืออาร์เรย์ C# หรือ List
ใช้ Set
ที่คุณจะใช้ Java/C# HashSet
ใช้ Map
ที่คุณจะใช้ Java HashMap
หรือ C# Dictionary
3. การพิมพ์แบบไดนามิกและแบบคงที่
ในภาษาแบบไดนามิก เช่น JavaScript, Ruby และ Python คุณสามารถอ้างอิงถึงสมาชิกได้แม้ว่าจะไม่มีอยู่จริงก็ตาม นี่คือตัวอย่าง JavaScript:
var person = {}; // create an empty object person.name = 'alice'; // add a member to the object if (person.age < 21) { // refer to a property that is not in the object // ... }
หากคุณเรียกใช้สิ่งนี้ person.age
จะเป็น undefined
แต่จะรันต่อไป
ในทำนองเดียวกัน คุณสามารถเปลี่ยนประเภทของตัวแปรใน JavaScript:
var a = 1; // a is a number a = 'one'; // a is now a string
ในทางตรงกันข้าม ใน Java คุณไม่สามารถเขียนโค้ดเหมือนข้างบนได้ เนื่องจากคอมไพเลอร์จำเป็นต้องรู้ประเภท และตรวจสอบว่าการดำเนินการทั้งหมดถูกกฎหมาย แม้ว่าคุณจะใช้คีย์เวิร์ด var:
var b = 1; // a is an int // b = "one"; // not allowed in Java
Java อนุญาตให้คุณเขียนโค้ดด้วยประเภทสแตติกเท่านั้น (คุณสามารถใช้วิปัสสนาเพื่อทำพฤติกรรมไดนามิกบางอย่างได้ แต่ไม่ใช่ส่วนหนึ่งของไวยากรณ์โดยตรง) JavaScript และภาษาไดนามิกล้วนอื่นๆ อนุญาตให้คุณเขียนโค้ดด้วยประเภทไดนามิกเท่านั้น
ภาษา Dart อนุญาตทั้ง:
// dart dynamic a = 1; // a is an int - dynamic typing a = 'one'; // a is now a string a.foo(); // we can call a function on a dynamic object, to be resolved at run time var b = 1; // b is an int - static typing // b = 'one'; // not allowed in Dart
Dart มี dynamic
หลอกซึ่งทำให้ลอจิกประเภททั้งหมดได้รับการจัดการที่รันไทม์ ความพยายามที่จะเรียก a.foo()
จะไม่รบกวนตัววิเคราะห์สแตติกและโค้ดจะทำงาน แต่จะล้มเหลวขณะรันไทม์เนื่องจากไม่มีวิธีการดังกล่าว
แต่เดิม C# นั้นเหมือนกับ Java และต่อมาได้เพิ่มการรองรับไดนามิก ดังนั้น Dart และ C# จึงใกล้เคียงกันในเรื่องนี้
4. ฟังก์ชั่น
ไวยากรณ์การประกาศฟังก์ชัน
ไวยากรณ์ของฟังก์ชันใน Dart นั้นเบากว่าเล็กน้อยและสนุกกว่าใน C # หรือ Java ไวยากรณ์เป็นอย่างใดอย่างหนึ่งเหล่านี้:
// functions as declarations return-type name (parameters) {body} return-type name (parameters) => expression; // function expressions (assignable to variables, etc.) (parameters) {body} (parameters) => expression
ตัวอย่างเช่น:

void printFoo() { print('foo'); }; String embellish(String s) => s.toUpperCase() + '!!'; var printFoo = () { print('foo'); }; var embellish = (String s) => s.toUpperCase() + '!!';
พารามิเตอร์ผ่าน
เนื่องจากทุกอย่างเป็นอ็อบเจ็กต์ รวมถึง primitives เช่น int
และ String
การส่งพารามิเตอร์อาจสร้างความสับสน แม้ว่าจะไม่มีพารามิเตอร์ ref
ที่ส่งผ่านเหมือนใน C# แต่ทุกอย่างจะถูกส่งผ่านโดยการอ้างอิง และฟังก์ชันไม่สามารถเปลี่ยนการอ้างอิงของผู้โทรได้ เนื่องจากอ็อบเจ็กต์จะไม่ถูกโคลนเมื่อส่งผ่านไปยังฟังก์ชัน ฟังก์ชันอาจเปลี่ยนคุณสมบัติของอ็อบเจ็กต์ อย่างไรก็ตาม ความแตกต่างสำหรับ primitives เช่น int และ String นั้นเป็นสิ่งที่น่าสงสัยอย่างมีประสิทธิภาพเนื่องจากประเภทเหล่านั้นจะไม่เปลี่ยนรูป
var id = 1; var name = 'alice'; var client = Client(); void foo(int id, String name, Client client) { id = 2; // local var points to different int instance name = 'bob'; // local var points to different String instance client.State = 'AK'; // property of caller's object is changed } foo(id, name, client); // id == 1, name == 'alice', client.State == 'AK'
พารามิเตอร์เสริม
หากคุณอยู่ในโลก C# หรือ Java คุณอาจสาปแช่งในสถานการณ์ด้วยวิธีโอเวอร์โหลดที่สับสนเช่นนี้:
// java void foo(string arg1) {...} void foo(int arg1, string arg2) {...} void foo(string arg1, Client arg2) {...} // call site: foo(clientId, input3); // confusing! too easy to misread which overload it is calling
หรือด้วยพารามิเตอร์ทางเลือก C# มีความสับสนอีกประเภทหนึ่ง:
// c# void Foo(string arg1, int arg2 = 0) {...} void Foo(string arg1, int arg3 = 0, int arg2 = 0) {...} // call site: Foo("alice", 7); // legal but confusing! too easy to misread which overload it is calling and which parameter binds to argument 7 Foo("alice", arg2: 9); // better
C# ไม่ต้องการการตั้งชื่ออาร์กิวเมนต์ทางเลือกที่ไซต์การโทร ดังนั้นการปรับโครงสร้างด้วยพารามิเตอร์ทางเลือกอาจเป็นอันตรายได้ หากไซต์การโทรบางแห่งถูกกฎหมายหลังจากรีแฟคเตอร์ คอมไพเลอร์จะไม่สามารถตรวจจับไซต์เหล่านั้นได้
Dart มีวิธีที่ปลอดภัยและยืดหยุ่นมาก ประการแรก ไม่ รองรับวิธีการโอเวอร์โหลด มีสองวิธีในการจัดการพารามิเตอร์ทางเลือกแทน:
// positional optional parameters void foo(string arg1, [int arg2 = 0, int arg3 = 0]) {...} // call site for positional optional parameters foo('alice'); // legal foo('alice', 12); // legal foo('alice', 12, 13); // legal // named optional parameters void bar(string arg1, {int arg2 = 0, int arg3 = 0}) {...} bar('alice'); // legal bar('alice', arg3: 12); // legal bar('alice', arg3: 12, arg2: 13); // legal; sequence can vary and names are required
คุณไม่สามารถใช้ทั้งสองสไตล์ในการประกาศฟังก์ชันเดียวกันได้
ตำแหน่งคีย์เวิร์ด async
C # มีตำแหน่งที่สับสนสำหรับคีย์เวิร์ด async
:
Task<int> Foo() {...} async Task<int> Foo() {...}
นี่หมายความว่าลายเซ็นของฟังก์ชันเป็นแบบอะซิงโครนัส แต่จริงๆ แล้วเฉพาะการใช้งานฟังก์ชันเท่านั้นที่ไม่ซิงโครนัส ลายเซ็นใดลายเซ็นหนึ่งข้างต้นจะเป็นการใช้งานอินเทอร์เฟซนี้อย่างถูกต้อง:
interface ICanFoo { Task<int> Foo(); }
ในภาษา Dart นั้น async
จะอยู่ในตำแหน่งที่สมเหตุสมผลมากกว่า ซึ่งแสดงว่าการใช้งานนั้นไม่พร้อมกัน:
Future<int> foo() async {...}
ขอบเขตและการปิด
เช่นเดียวกับ C # และ Java Dart มีขอบเขตคำศัพท์ ซึ่งหมายความว่าตัวแปรที่ประกาศในบล็อกนั้นอยู่นอกขอบเขตที่ส่วนท้ายของบล็อก ดังนั้น Dart จัดการกับการปิดในลักษณะเดียวกัน
ไวยากรณ์คุณสมบัติ
Java ทำให้รูปแบบ get/set เป็นที่นิยม แต่ภาษาไม่มีไวยากรณ์พิเศษใดๆ สำหรับมัน:
// java private String clientName; public String getClientName() { return clientName; } public void setClientName(String value}{ clientName = value; }
C # มีไวยากรณ์สำหรับมัน:
// c# private string clientName; public string ClientName { get { return clientName; } set { clientName = value; } }
Dart มีคุณสมบัติรองรับไวยากรณ์ที่แตกต่างกันเล็กน้อย:
// dart string _clientName; string get ClientName => _clientName; string set ClientName(string s) { _clientName = s; }
5. ตัวสร้าง
ตัวสร้าง Dart มีความยืดหยุ่นมากกว่าใน C # หรือ Java เล็กน้อย คุณลักษณะที่ดีอย่างหนึ่งคือความสามารถในการตั้งชื่อคอนสตรัคเตอร์ที่แตกต่างกันในคลาสเดียวกัน:
class Point { Point(double x, double y) {...} // default ctor Point.asPolar(double angle, double r) {...} // named ctor }
คุณสามารถเรียกคอนสตรัคเตอร์เริ่มต้นได้ด้วยชื่อคลาส: var c = Client();
มีการจดชวเลขสองประเภทสำหรับการเริ่มต้นสมาชิกของอินสแตนซ์ก่อนที่จะเรียกตัวสร้างเนื้อหา:
class Client { String _code; String _name; Client(String this._name) // "this" shorthand for assigning parameter to instance member : _code = _name.toUpper() { // special out-of-body place for initializing // body } }
ตัวสร้างสามารถเรียกใช้ตัวสร้าง superclass และเปลี่ยนเส้นทางไปยังตัวสร้างอื่นในคลาสเดียวกัน:
Foo.constructor1(int x) : this(x); // redirect to the default ctor in same class; no body allowed Foo.constructor2(int x) : super.plain(x) {...} // call base class named ctor, then run this body Foo.constructor3(int x) : _b = x + 1 : super.plain(x) {...} // initialize _b, then call base class ctor, then run this body
ตัวสร้างที่เรียกใช้ตัวสร้างอื่นในคลาสเดียวกันใน Java และ C# อาจสร้างความสับสนได้เมื่อทั้งคู่มีการนำไปใช้งาน ใน Dart ข้อ จำกัด ที่การเปลี่ยนเส้นทางคอนสตรัคเตอร์ไม่สามารถมีเนื้อความได้บังคับให้โปรแกรมเมอร์ทำให้เลเยอร์ของคอนสตรัคเตอร์ชัดเจนขึ้น
นอกจากนี้ยังมีคีย์เวิร์ดของ factory
ที่อนุญาตให้ใช้ฟังก์ชันได้เหมือนตัวสร้าง แต่การใช้งานเป็นเพียงฟังก์ชันปกติ คุณสามารถใช้เพื่อส่งคืนอินสแตนซ์แคชหรืออินสแตนซ์ของประเภทที่ได้รับ:
class Shape { factory Shape(int nsides) { if (nsides == 4) return Square(); // etc. } } var s = Shape(4);
6. ตัวดัดแปลง
ใน Java และ C# เรามีตัวแก้ไขการเข้าถึง เช่น private
, protected
และ public
ใน Dart สิ่งนี้ทำให้ง่ายขึ้นอย่างมาก: หากชื่อสมาชิกเริ่มต้นด้วยขีดล่าง จะเห็นได้ทุกที่ในแพ็คเกจ (รวมถึงจากคลาสอื่น) และซ่อนจากผู้โทรภายนอก มิฉะนั้นจะมองเห็นได้จากทุกที่ ไม่มีคีย์เวิร์ดที่เหมือนกับ private
ที่บ่งบอกถึงการมองเห็น
ตัวดัดแปลงอีกประเภทหนึ่งควบคุมความสามารถในการเปลี่ยนแปลง: คำหลัก final
และค่า const
มีไว้เพื่อจุดประสงค์นั้น แต่มีความหมายต่างกัน:
var a = 1; // a is variable, and can be reassigned later final b = a + 1; // b is a runtime constant, and can only be assigned once const c = 3; // c is a compile-time constant // const d = a + 2; // not allowed because a+2 cannot be resolved at compile time
7. ลำดับชั้นของคลาส
ภาษา Dart รองรับอินเตอร์เฟส คลาส และการสืบทอดหลายประเภท อย่างไรก็ตาม ไม่มีคำสำคัญเกี่ยวกับ interface
แทน ทุกคลาสยังเป็นอินเตอร์เฟส ดังนั้นคุณสามารถกำหนดคลาส abstract
แล้วนำไปใช้:
abstract class HasDesk { bool isDeskMessy(); // no implementation here } class Employee implements HasDesk { bool isDeskMessy() { ...} // must be implemented here }
การสืบทอดหลายรายการเสร็จสิ้นด้วยสายเลือดหลักโดยใช้คีย์เวิร์ด extends
และคลาสอื่นๆ โดยใช้คีย์เวิร์ด with
:
class Employee extends Person with Salaried implements HasDesk {...}
ในการประกาศนี้ คลาส Employee
มาจาก Person
และ Salaried
แต่ Person
เป็น superclass หลัก และ Salaried
คือ mixin (superclass รอง)
8. ผู้ประกอบการ
มีโอเปอเรเตอร์ Dart ที่สนุกและมีประโยชน์ที่เราไม่คุ้นเคย
Cascades ช่วยให้คุณใช้รูปแบบการผูกมัดกับอะไรก็ได้:
emp ..name = 'Alice' ..supervisor = 'Zoltron' ..hire();
ตัวดำเนินการสเปรดอนุญาตให้ดำเนินการกับคอลเล็กชันเสมือนเป็นรายการองค์ประกอบในเครื่องมือเริ่มต้น:
var smallList = [1, 2]; var bigList = [0, ...smallList, 3, 4]; // [0, 1, 2, 3, 4]
9. หัวข้อ
Dart ไม่มีเธรด ซึ่งอนุญาตให้ทรานสไพล์ไปยัง JavaScript มี "ไอโซเลท" แทน ซึ่งคล้ายกับกระบวนการที่แยกจากกัน ในแง่ที่ว่าพวกเขาไม่สามารถแบ่งปันหน่วยความจำได้ เนื่องจากการเขียนโปรแกรมแบบมัลติเธรดมักเกิดข้อผิดพลาดได้ง่าย ความปลอดภัยนี้จึงถูกมองว่าเป็นข้อดีอย่างหนึ่งของ Dart ในการสื่อสารระหว่างไอโซเลท คุณต้องสตรีมข้อมูลระหว่างไอโซเลท วัตถุที่ได้รับจะถูกคัดลอกลงในพื้นที่หน่วยความจำของตัวรับแยก
พัฒนาด้วยภาษาปาเป้า: คุณทำได้!
หากคุณเป็นนักพัฒนา C# หรือ Java สิ่งที่คุณรู้อยู่แล้วจะช่วยให้คุณเรียนรู้ภาษา Dart ได้อย่างรวดเร็ว เนื่องจากถูกออกแบบให้คุ้นเคย ด้วยเหตุนี้ เราจึงได้รวบรวม PDF cheat sheet PDF สำหรับการอ้างอิงของคุณ โดยเน้นที่ความแตกต่างที่สำคัญจาก C# และ Java ที่เทียบเท่ากัน:
ความแตกต่างที่แสดงในบทความนี้รวมกับความรู้ที่มีอยู่จะช่วยให้คุณมีประสิทธิผลภายในวันแรกหรือสองวันแรกของ Dart มีความสุขในการเข้ารหัส!