Dart is a single threaded, general purpose programming language. It borrows a lot from other mainstream languages. It supports Streams, Futures(known as Promises in JavaScript), Generics, First-class functions(closures) and static type checking. Dart can run in any platform such as Web, CLI, Desktop, Mobile and IoT devices.
Dart’s most controversial feature is its Optional Typing Static Type safety and Sound Type checks.
1import "dart:collection";
2import "dart:math" as math;
3
4/// Welcome to Learn Dart in 15 minutes. http://dart.dev/
5/// This is an executable tutorial. You can run it with Dart or on
6/// the Try Dart! site if you copy/paste it there. http://dartpad.dev/
7/// You can also run Flutter in DartPad by click the `< > New Pad ` and choose Flutter
8
9
10/// In Dart, Everything is an Object.
11/// Every declaration of an object is an instance of Null and
12/// Null is also an object.
13
14
15/// 3 Types of comments in dart
16// Single line comment
17/**
18* Multi-line comment
19* Can comment several lines
20*/
21/// Code doc comment
22/// It uses markdown syntax to generate code docs when making an API.
23/// Code doc comment is the recommended choice when documenting your APIs, classes and methods.
24
25/// 4 types of variable declaration.
26/// Constants are variables that are immutable cannot be change or altered.
27/// `const` in dart should practice SCREAMING_SNAKE_CASE name declaration.
28const CONSTANT_VALUE = "I CANNOT CHANGE";
29CONSTANT_VALUE = "DID I?"; //Error
30/// Final is another variable declaration that cannot be change once it has been instantiated. Commonly used in classes and functions
31/// `final` can be declared in pascalCase.
32final finalValue = "value cannot be changed once instantiated";
33finalValue = "Seems not"; //Error
34
35/// `var` is another variable declaration that is mutable and can change its value. Dart will infer types and will not change its data type
36var mutableValue = "Variable string";
37mutableValue = "this is valid";
38mutableValue = false; // Error.
39
40/// `dynamic` is another variable declaration in which the type is not evaluated by the dart static type checking.
41/// It can change its value and data type.
42/// Some dartisans uses dynamic cautiously as it cannot keep track of its data type. so use it at your own risk
43dynamic dynamicValue = "I'm a string";
44dynamicValue = false; // false
45
46
47/// Functions can be declared in a global space
48/// Function declaration and method declaration look the same. Function
49/// declarations can be nested. The declaration takes the form of
50/// name() {} or name() => singleLineExpression;
51/// The fat arrow function declaration can be an implicit or
52/// explicit return for the result of the expression.
53/// Dart will execute a function called `main()` anywhere in the dart project.
54///
55example1() {
56 nested1() {
57 nested2() => print("Example1 nested 1 nested 2");
58 nested2();
59 }
60
61 nested1();
62}
63
64/// Anonymous functions don't include a name
65example2() {
66 //// Explicit return type.
67 nested1(void Function() fn) {
68 fn();
69 }
70 nested1(() => print("Example2 nested 1"));
71}
72
73/// When a function parameter is declared, the declaration can include the
74/// number of parameters the function takes by explicitly specifying the names of the
75/// parameters it takes.
76example3() {
77 planA(fn(String informSomething)) {
78 fn("Example3 plan A");
79 }
80 planB(fn) {
81 // Or don't declare number of parameters.
82 fn("Example3 plan B");
83 }
84
85 planA((s) => print(s));
86 planB((s) => print(s));
87}
88
89/// Functions have closure access to outer variables.
90/// Dart will infer types when the variable has a value of something.
91/// In this example dart knows that this variable is a String.
92var example4Something = "Example4 nested 1";
93example4() {
94 nested1(fn(informSomething)) {
95 fn(example4Something);
96 }
97
98 nested1((s) => print(s));
99}
100
101/// Class declaration with a sayIt method, which also has closure access
102/// to the outer variable as though it were a function as seen before.
103var example5method = "Example5 sayIt";
104
105class Example5Class {
106 sayIt() {
107 print(example5method);
108 }
109}
110
111example5() {
112 /// Create an anonymous instance of the Example5Class and call the sayIt
113 /// method on it.
114 /// the `new` keyword is optional in Dart.
115 new Example5Class().sayIt();
116}
117
118/// Class declaration takes the form of class name { [classBody] }.
119/// Where classBody can include instance methods and variables, but also
120/// class methods and variables.
121class Example6Class {
122 var instanceVariable = "Example6 instance variable";
123 sayIt() {
124 print(instanceVariable);
125 }
126}
127
128example6() {
129 Example6Class().sayIt();
130}
131
132/// Class methods and variables are declared with "static" terms.
133class Example7Class {
134 static var classVariable = "Example7 class variable";
135 static sayItFromClass() {
136 print(classVariable);
137 }
138
139 sayItFromInstance() {
140 print(classVariable);
141 }
142}
143
144example7() {
145 Example7Class.sayItFromClass();
146 new Example7Class().sayItFromInstance();
147}
148
149/// Dart supports Generics.
150/// Generics refers to the technique of writing the code for a class
151/// without specifying the data type(s) that the class works on.
152/// Source: https://stackoverflow.com/questions/4560890/what-are-generics-in-c
153
154/// Type `T` refers to any type that has been instantiated
155/// you can call whatever you want
156/// Programmers uses the convention in the following
157/// T - Type(used for class and primitype types)
158/// E - Element(used for List, Set, or Iterable)
159/// K,V - Key Value(used for Map)
160class GenericExample<T>{
161 void printType(){
162 print("$T");
163 }
164 // methods can also have generics
165 genericMethod<M>(){
166 print("class:$T, method: $M");
167 }
168}
169
170
171/// List are similar to arrays but list is a child of Iterable<E>
172/// Therefore Maps, List, LinkedList are all child of Iterable<E> to be able to loop using the keyword `for`
173/// Important things to remember:
174/// () - Iterable<E>
175/// [] - List<E>
176/// {} - Map<K,V>
177
178
179/// List are great, but there's a restriction for what List can be
180/// outside of function/method bodies. List on the outer scope of class
181/// or outside of class have to be constant. Strings and numbers are constant
182/// by default. But arrays and maps are not. They can be made constant by
183/// declaring them "const". Kind of similar to JavaScript's Object.freeze()
184const example8List = ["Example8 const array"];
185const example8Map = {"someKey": "Example8 const map"};
186/// Declare List or Maps as Objects.
187 List<String> explicitList = new List<String>.empty();
188 Map<String,dynamic> explicitMaps = new Map<String,dynamic>();
189
190example8() {
191 explicitList.add("SomeArray");
192 print(example8Map["someKey"]);
193 print(explicitList[0]);
194
195 /// Assigning a list from one variable to another will not be the same result.
196 /// Because dart is pass-reference-by-value.
197 /// So when you assign an existing list to a new variable.
198 /// Instead of List, it becomes an Iterable
199 var iterableExplicitList = explicitList;
200 print(iterableExplicitList); // ("SomeArray"); "[]" becomes "()"
201 var newExplicitLists = explicitList.toList(); // Converts Iterable<E> to List<E>
202}
203
204/// Loops in Dart take the form of standard for () {} or while () {} loops,
205/// slightly more modern for (.. in ..) {}, or functional callbacks with many
206/// supported features, starting with forEach,map and where.
207var example9Array = const ["a", "b"];
208example9() {
209 for (int i = 0; i < example9Array.length; i++) {
210 print("Example9 for loop '${example9Array[i]}'");
211 }
212 var i = 0;
213 while (i < example9Array.length) {
214 print("Example9 while loop '${example9Array[i]}'");
215 i++;
216 }
217 for (final e in example9Array) {
218 print("Example9 for-in loop '${e}'");
219 }
220
221 example9Array.forEach((e) => print("Example9 forEach loop '${e}'"));
222
223}
224
225/// To loop over the characters of a string or to extract a substring.
226var example10String = "ab";
227example10() {
228 for (var i = 0; i < example10String.length; i++) {
229 print("Example10 String character loop '${example10String[i]}'");
230 }
231 for (var i = 0; i < example10String.length; i++) {
232 print("Example10 substring loop '${example10String.substring(i, i + 1)}'");
233 }
234}
235
236/// `int`, `double` and `num` are the three supported number formats.
237/// `num` can be either `int` or `double`.
238/// `int` and `double` are children of type `num`
239example11() {
240 var i = 1 + 320, d = 3.2 + 0.01;
241 final num myFinalNumDouble = 2.2;
242 final num myFinalNumInt = 2;
243 final int myFinalInt = 1;
244 final double myFinalDouble = 0.1;
245 num myNumDouble = 2.2;
246 num myNumInt = 2;
247 int myInt = 1;
248 double myDouble = 0; // Dart will add decimal prefix, becomes 0.0;
249 myNumDouble = myFinalInt; // valid
250 myNumDouble = myFinalDouble; // valid
251 myNumDouble = myFinalNumInt; // valid
252
253 myInt = myNumDouble; // error
254 myInt = myFinalDouble; // error
255 myInt = myFinalNumInt; // error (implicit downcasts removed in Dart 2.9)
256 myInt = myFinalNumInt as int; // valid
257
258 myDouble = myFinalInt; // error
259 myDouble = myFinalNumInt; // error
260 myDouble = myFinalNumDouble; // error (implicit downcasts removed in Dart 2.9)
261 myDouble = myFinalNumDouble as double; // valid
262
263 print("Example11 int ${i}");
264 print("Example11 double ${d}");
265
266}
267
268/// DateTime provides date/time arithmetic.
269example12() {
270 var now = new DateTime.now();
271 print("Example12 now '${now}'");
272 now = now.add(new Duration(days: 1));
273 print("Example12 tomorrow '${now}'");
274}
275
276/// Regular expressions are supported.
277example13() {
278 var s1 = "some string", s2 = "some", re = new RegExp("^s.+?g\$");
279 match(s) {
280 if (re.hasMatch(s)) {
281 print("Example13 regexp matches '${s}'");
282 } else {
283 print("Example13 regexp doesn't match '${s}'");
284 }
285 }
286
287 match(s1);
288 match(s2);
289}
290
291/// Boolean expressions support implicit conversions and dynamic type
292example14() {
293 var a = true;
294 if (a) {
295 print("true, a is $a");
296 }
297 a = false;
298 if (a) {
299 print("true, a is $a");
300 } else {
301 print("false, a is $a"); /// runs here
302 }
303
304 /// dynamic typed null can not be convert to bool
305 var b; /// b is dynamic type
306 b = "abc";
307 try {
308 if (b) {
309 print("true, b is $b");
310 } else {
311 print("false, b is $b");
312 }
313 } catch (e) {
314 print("error, b is $b"); /// this could be run but got error
315 }
316 b = null;
317 if (b) { /// Failed assertion: boolean expression must not be null)
318 print("true, b is $b");
319 } else {
320 print("false, b is $b");
321 }
322
323 /// statically typed null can not be convert to bool
324 var c = "abc";
325 c = null;
326 /// compilation failed
327 /// if (c) {
328 /// print("true, c is $c");
329 /// } else {
330 /// print("false, c is $c");
331 /// }
332}
333
334/// try/catch/finally and throw are used for exception handling.
335/// throw takes any object as parameter;
336example15() {
337 try {
338 try {
339 throw "Some unexpected error.";
340 } catch (e) {
341 print("Example15 an exception: '${e}'");
342 throw e; /// Re-throw
343 }
344 } catch (e) {
345 print("Example15 catch exception being re-thrown: '${e}'");
346 } finally {
347 print("Example15 Still run finally");
348 }
349}
350
351/// To be efficient when creating a long string dynamically, use
352/// StringBuffer. Or you could join a string array.
353example16() {
354 var sb = new StringBuffer(), a = ["a", "b", "c", "d"], e;
355 for (e in a) {
356 sb.write(e);
357 }
358 print("Example16 dynamic string created with "
359 "StringBuffer '${sb.toString()}'");
360 print("Example16 join string array '${a.join()}'");
361}
362
363/// Strings can be concatenated by just having string List next to
364/// one another with no further operator needed.
365
366example17() {
367 print("Example17 "
368 "concatenate "
369 "strings "
370 "just like that");
371}
372
373/// Strings have single-quote or double-quote for delimiters with no
374/// actual difference between the two. The given flexibility can be good
375/// to avoid the need to escape content that matches the delimiter being
376/// used. For example, double-quotes of HTML attributes if the string
377/// contains HTML content.
378example18() {
379 print('Example18 <a href="etc">'
380 "Don't can't I'm Etc"
381 '</a>');
382}
383
384/// Strings with triple single-quotes or triple double-quotes span
385/// multiple lines and include line delimiters.
386example19() {
387 print('''Example19 <a href="etc">
388Example19 Don't can't I'm Etc
389Example19 </a>''');
390}
391
392/// Strings have the nice interpolation feature with the $ character.
393/// With $ { [expression] }, the return of the expression is interpolated.
394/// $ followed by a variable name interpolates the content of that variable.
395/// $ can be escaped like so \$ to just add it to the string instead.
396example20() {
397 var s1 = "'\${s}'", s2 = "'\$s'";
398 print("Example20 \$ interpolation ${s1} or $s2 works.");
399}
400
401/// Optional types allow for the annotation of APIs and come to the aid of
402/// IDEs so the IDEs can better refactor, auto-complete and check for
403/// errors. So far we haven't declared any types and the programs have
404/// worked just fine. In fact, types are disregarded during runtime.
405/// Types can even be wrong and the program will still be given the
406/// benefit of the doubt and be run as though the types didn't matter.
407/// There's a runtime parameter that checks for type errors which is
408/// the checked mode, which is said to be useful during development time,
409/// but which is also slower because of the extra checking and is thus
410/// avoided during deployment runtime.
411class Example21 {
412 List<String> _names = [];
413 Example21() {
414 _names = ["a", "b"];
415 }
416 List<String> get names => _names;
417 set names(List<String> list) {
418 _names = list;
419 }
420
421 int get length => _names.length;
422 void add(String name) {
423 _names.add(name);
424 }
425}
426
427void example21() {
428 Example21 o = new Example21();
429 o.add("c");
430 print("Example21 names '${o.names}' and length '${o.length}'");
431 o.names = ["d", "e"];
432 print("Example21 names '${o.names}' and length '${o.length}'");
433}
434
435/// Class inheritance takes the form of class name extends AnotherClassName {}.
436class Example22A {
437 var _name = "Some Name!";
438 get name => _name;
439}
440
441class Example22B extends Example22A {}
442
443example22() {
444 var o = new Example22B();
445 print("Example22 class inheritance '${o.name}'");
446}
447
448/// Class mixin is also available, and takes the form of
449/// class name extends SomeClass with AnotherClassName {}.
450/// It's necessary to extend some class to be able to mixin another one.
451/// The template class of mixin cannot at the moment have a constructor.
452/// Mixin is mostly used to share methods with distant classes, so the
453/// single inheritance doesn't get in the way of reusable code.
454/// Mixins follow the "with" statement during the class declaration.
455class Example23A {}
456
457/// Since Dart 3 the 'mixin' keyword is required instead of 'class'.
458mixin Example23Utils {
459 addTwo(n1, n2) {
460 return n1 + n2;
461 }
462}
463
464class Example23B extends Example23A with Example23Utils {
465 addThree(n1, n2, n3) {
466 return addTwo(n1, n2) + n3;
467 }
468}
469
470example23() {
471 var o = new Example23B(), r1 = o.addThree(1, 2, 3), r2 = o.addTwo(1, 2);
472 print("Example23 addThree(1, 2, 3) results in '${r1}'");
473 print("Example23 addTwo(1, 2) results in '${r2}'");
474}
475
476/// The Class constructor method uses the same name of the class and
477/// takes the form of SomeClass() : super() {}, where the ": super()"
478/// part is optional and it's used to delegate constant parameters to the
479/// super-parent's constructor.
480class Example24A {
481 var _value;
482 Example24A({value = "someValue"}) {
483 _value = value;
484 }
485 get value => _value;
486}
487
488class Example24B extends Example24A {
489 Example24B({value = "someOtherValue"}) : super(value: value);
490}
491
492example24() {
493 var o1 = new Example24B(), o2 = new Example24B(value: "evenMore");
494 print("Example24 calling super during constructor '${o1.value}'");
495 print("Example24 calling super during constructor '${o2.value}'");
496}
497
498/// There's a shortcut to set constructor parameters in case of simpler classes.
499/// Just use the this.parameterName prefix and it will set the parameter on
500/// an instance variable of same name.
501class Example25 {
502 var value, anotherValue;
503 Example25({this.value, this.anotherValue});
504}
505
506example25() {
507 var o = new Example25(value: "a", anotherValue: "b");
508 print("Example25 shortcut for constructor '${o.value}' and "
509 "'${o.anotherValue}'");
510}
511
512/// Named parameters are available when declared between {}.
513/// Parameter order can be optional when declared between {}.
514/// Parameters can be made optional when declared between [].
515example26() {
516 var _name, _surname, _email;
517 setConfig1({name, surname}) {
518 _name = name;
519 _surname = surname;
520 }
521
522 setConfig2(name, [surname, email]) {
523 _name = name;
524 _surname = surname;
525 _email = email;
526 }
527
528 setConfig1(surname: "Doe", name: "John");
529 print("Example26 name '${_name}', surname '${_surname}', "
530 "email '${_email}'");
531 setConfig2("Mary", "Jane");
532 print("Example26 name '${_name}', surname '${_surname}', "
533 "email '${_email}'");
534}
535
536/// Variables declared with final can only be set once.
537/// In case of classes, final instance variables can be set via constant
538/// constructor parameter.
539class Example27 {
540 final color1, color2;
541 /// A little flexibility to set final instance variables with syntax
542 /// that follows the :
543 Example27({this.color1, color2}) : color2 = color2;
544}
545
546example27() {
547 final color = "orange", o = new Example27(color1: "lilac", color2: "white");
548 print("Example27 color is '${color}'");
549 print("Example27 color is '${o.color1}' and '${o.color2}'");
550}
551
552/// To import a library, use import "libraryPath" or if it's a core library,
553/// import "dart:libraryName". There's also the "pub" package management with
554/// its own convention of import "package:packageName".
555/// See import "dart:collection"; at the top. Imports must come before
556/// other code declarations. IterableBase comes from dart:collection.
557class Example28 extends IterableBase {
558 var names;
559 Example28() {
560 names = ["a", "b"];
561 }
562 get iterator => names.iterator;
563}
564
565example28() {
566 var o = new Example28();
567 o.forEach((name) => print("Example28 '${name}'"));
568}
569
570/// For control flow we have:
571/// * standard switch with must break statements
572/// * if-else if-else and ternary ..?..:.. operator
573/// * closures and anonymous functions
574/// * break, continue and return statements
575example29() {
576 var v = true ? 30 : 60;
577 switch (v) {
578 case 30:
579 print("Example29 switch statement");
580 break;
581 }
582 if (v < 30) {
583 } else if (v > 30) {
584 } else {
585 print("Example29 if-else statement");
586 }
587 callItForMe(fn()) {
588 return fn();
589 }
590
591 rand() {
592 v = new math.Random().nextInt(50);
593 return v;
594 }
595
596 while (true) {
597 print("Example29 callItForMe(rand) '${callItForMe(rand)}'");
598 if (v != 30) {
599 break;
600 } else {
601 continue;
602 }
603 /// Never gets here.
604 }
605}
606
607/// Parse int, convert double to int, or just keep int when dividing numbers
608/// by using the ~/ operation. Let's play a guess game too.
609example30() {
610 var gn,
611 tooHigh = false,
612 n,
613 n2 = (2.0).toInt(),
614 top = int.parse("123") ~/ n2,
615 bottom = 0;
616 top = top ~/ 6;
617 gn = new math.Random().nextInt(top + 1); /// +1 because nextInt top is exclusive
618 print("Example30 Guess a number between 0 and ${top}");
619 guessNumber(i) {
620 if (n == gn) {
621 print("Example30 Guessed right! The number is ${gn}");
622 } else {
623 tooHigh = n > gn;
624 print("Example30 Number ${n} is too "
625 "${tooHigh ? 'high' : 'low'}. Try again");
626 }
627 return n == gn;
628 }
629
630 n = (top - bottom) ~/ 2;
631 while (!guessNumber(n)) {
632 if (tooHigh) {
633 top = n - 1;
634 } else {
635 bottom = n + 1;
636 }
637 n = bottom + ((top - bottom) ~/ 2);
638 }
639}
640
641/// Optional Positional Parameter:
642/// parameter will be disclosed with square bracket [ ] & square bracketed parameter are optional.
643example31() {
644 findVolume31(int length, int breath, [int? height]) {
645 print('length = $length, breath = $breath, height = $height');
646 }
647
648 findVolume31(10,20,30); //valid
649 findVolume31(10,20); //also valid
650}
651
652/// Optional Named Parameter:
653/// parameter will be disclosed with curly bracket { }
654/// curly bracketed parameter are optional.
655/// have to use parameter name to assign a value which separated with colan :
656/// in curly bracketed parameter order does not matter
657/// these type parameter help us to avoid confusion while passing value for a function which has many parameter.
658example32() {
659 findVolume32(int length, int breath, {int? height}) {
660 print('length = $length, breath = $breath, height = $height');
661 }
662
663 findVolume32(10,20,height:30);//valid & we can see the parameter name is mentioned here.
664 findVolume32(10,20);//also valid
665}
666
667/// Optional Default Parameter:
668/// same like optional named parameter in addition we can assign default value for this parameter.
669/// which means no value is passed this default value will be taken.
670example33() {
671 findVolume33(int length, int breath, {int height=10}) {
672 print('length = $length, breath = $breath, height = $height');
673 }
674
675 findVolume33(10,20,height:30);//valid
676 findVolume33(10,20);//valid
677}
678
679/// Dart has also added feature such as Null aware operators
680var isBool = true;
681var hasString = isBool ?? "default String";
682
683/// Programs have only one entry point in the main function.
684/// Nothing is expected to be executed on the outer scope before a program
685/// starts running with what's in its main function.
686/// This helps with faster loading and even lazily loading of just what
687/// the program needs to startup with.
688main() {
689 print("Learn Dart in 15 minutes!");
690 [
691 example1, example2, example3, example4, example5,
692 example6, example7, example8, example9, example10,
693 example11, example12, example13, example14, example15,
694 example16, example17, example18, example19, example20,
695 example21, example22, example23, example24, example25,
696 example26, example27, example28, example29,
697 example30 // Adding this comment stops the dart formatter from putting all items on a new line
698 ].forEach((ef) => ef());
699}
Further Reading ¶
Dart has a comprehensive web-site. It covers API reference, tutorials, articles and more, including a useful DartPad (a cloud-based Dart coding playground). https://dart.dev/ https://dartpad.dev/