Dart Reference
Notes on the Dart language
Updated: 03 September 2023
Notes from the The Net Ninja Youtube Series
To get started with Dart you can use DartPad
Hello World
A simple Hello World in dart looks like so:
1void main() {2 print("Hello World");3}
In Dart we require semicolons and the entrypoint is the main
function
Variables
We declare variables like this:
1int age = 5;2print(age);
Some data types are:
int
String
which can use a'
or a"
bool
dynamic
We can also define variables as dynamic
which means that their type can be changed
String interpolation can also be done like so:
1int age = 5;2String name = "John";3String person = "My name is $name and I am $age years old";
Functions
Functions make use of the following structure:
1MyType fName() {2 ...//do stuff3
4 return thing; //type of MyType5}
If a function has a single line we can also make use of an arrow function which looks like this:
1MyType getThing() => thing;
A function with inputs is defined and used like so:
1int add(int x, int y) => x + y;
And used as you’d expect:
1int result = add(1,3);
Functions can also take in optional params, there are two methods for this, named and unnamed params:
1// unnamed2int sumUN(int a, int b, [int c, int d]) => ....3
4//named5int sumN(int a, int b, {int c, int d}) => ...
The way we call these functions differ
1// unnamed2sumUN(1,2)3sumUN(1,2,3)4sumUN(1,2,3,4)5
6//named7sumN(1,2)8sumN(1,2, {c: 3})9sumN(1,2, {c: 3, d: 4})10```11
12# Lists13
14Lists in Dart are defined using the `[]` notation15
16```dart17List names = ['john', 'jeff', 'johnny'];
We can also use list methods to work with the list
1names.add('sally');2names.add(12); // not a string3
4names.remove('john');
The list as defined above does not have a defined type, usually we want to specify the allowable types (coz obviously). We can set the type using the <T>
notation like so:
1List<String> names = ['john', 'jeff', 'johnny'];
We also have methods available for lists such as the map
function which will return an IEnumerable
:
1myList.map((el){2 // do stuff3 return el;4})
And additionally the toList
method which will allow us to convert the above back into a list
1myList.map((el){2 // do stuff3 return el;4}).toList()
Classes
Classes are defined using the class
keyword, with the properties defined within the class. The new
keyword is not needed
1void main() {2 Person john = Person("John", 3);3 john.greet();4
5 john.setAge(5);6
7 print(john.getAge());8}9
10class Person {11 String name; // public by default12 int _age; // private if starts with _13
14 Person(String name, int age){15 this.name = name;16 this._age = age;17 }18
19 void greet() =>20 print("Hello, I am " + name);21
22 void setAge(int newAge) {23 this._age = newAge;24 }25
26
27 int getAge() => this._age;28}
Private properties start with
_
and cannot be accessed from outside the class
We can also initialize class variables like this:
1class Person {2 String name = "Person";3 int _age = 1;4 ...5}
We can use inheritance using the extends
keyword:
1class NotCat {2 bool isCat = false;3 String description = "Not a Kitty";4
5 NotCat(bool isCat){6 // we don't care7 }8}9
10class Person extends NotCat {11 String name; // public by default12 int _age; // private if starts with _13
14 Person(String name, int age): super(false){15 this.name = name;16 this._age = age;17 }18}
When using the above we need to be sure to also call the constructor of the base class from the inheriting class using super
Const and Final
A const
variable is one that’s value is constant at compile time, a final
variable is one that is only assigned to once
In dart we can also define constants using the const
and final
keywords like so:
1const int age = 12;2final String name= "John";3final Person myPerson = Person(name, age);
You can also create constant instances of objects but that requres a const
constructor
If we have a class with a constructor but we want to use it as a const constructor, we can do so by using the final
keyword for our property, and the below notation for the constructor:
1class QuoteCard extends StatelessWidget {2
3 final Quote quote;4 QuoteCard({this.quote});5 ...6}
We can then create an instance of this like so:
1var myCard = QuoteCard(quote: myQuote)
Maps
Maps are like dictionaries/key-value pairs
To create a map we use the Map
data type and the []
accessor:
1Map person = {2 "name": "Jeff Smith",3 "age": 644};5
6
7print(person["name"])
This is used in flutter when doing routing for pages
Async
Async code is code that finishes some time after being called but is not blocking. We use a combination of async
, await
, and Futures
Futures
A function that makes use of a Future that simply does a delay looks like this:
1void getData(){2 Future.delayed(Duration(seconds: 3), (){3 // callback function4 print("Callback activated")5 });6}
The callback is run when the future completes. This is similar to Promise
in JavaScript
We can then call the above function from our initState
function. A complete example would be something like this:
1class _SelectLocationState extends State<SelectLocation> {2 String name = "FETCHING NAME";3
4 void getData() {5 Future.delayed(Duration(seconds: 2), () {6 // callback function, will run after 2 seconds7 setState(() {8 name = "Johnny";9 });10 });11 }12
13 @override14 void initState() {15 super.initState();16 getData();17 }18
19 @override20 Widget build(BuildContext context) {21 return Scaffold(22 backgroundColor: Colors.purple,23 appBar: AppBar(24 title: Text("Select Location"),25 elevation: 0,26 backgroundColor: Colors.purple,27 ),28 body: Text(name),29 );30 }31}
Async/Await
Sometimes however we have some asynchronous code that needs to run sequentially we can make use of async
and await
Similar to other languages, Futures
(promises) can be awaited within an async
function. If we wanted to make our getData
function run more sequentially we can do something like this (note we also added async
to the function definition):
1String name = "FETCHING NAME";2String bio = "FETCHING BIO";3
4void getData() async {5 String userName = await Future.delayed(Duration(seconds: 2), () {6 // callback function7 return "Johnny";8 });9
10 String userBio = await Future.delayed(Duration(seconds: 2), () {11 return "$userName's Bio. Here are more things about $userName";12 });13
14 setState(() {15 name = userName;16 bio = userBio;17 });18}
Exceptions
To handle exceptions in dart we can use a try-catch
:
1try {2 // do some stuff3} catch(e) {4 // handle the exception5}
We can also use an optional finally
1try {2 doStuff();3 setState(() {4 hasError = false;5 });6} catch (e) {7 setState(() {8 hasError = true;9 });10} finally {11 setState(() {12 isLoading = false;13 });14}
Cascade operator
Dart has a cascade operator ..
which allows a function to return the instance of the initial object and not the result of a function call:
1void main() {2 var person = Person();3
4 // normal function call returns result5 print(person.haveBirthday()); // out: 16
7 // cascaded function call returns person8 print(person..haveBirthday()); // out: Instance of 'Person'9
10}11
12class Person {13 int age = 0;14 int haveBirthday() {15 age ++;16 return age;17 }18}
Or from the documentation:
“Cascades (..) allow you to make a sequence of operations on the same object. In addition to function calls, you can also access fields on that same object. This often saves you the step of creating a temporary variable and allows you to write more fluid code.”
1querySelector('#confirm') // Get an object.2 ..text = 'Confirm' // Use its members.3 ..classes.add('important')4 ..onClick.listen((e) => window.alert('Confirmed!'));
Conditionals
If-Else
1if (isCar) {2 print("Car");3} else {4 print("Not Car");5}
With multiple conditions:
1int age = 12;2
3if (age > 35) {4 // do stuff5} else if (age > 20) {6 // do stuff7} else if (age > 10) {8 // do stuff9} else {10 // do stuff11}
Ternary
We can use a ternary operator like so:
1bool isCar = thing == "Car" ? true : false
The ternary operator doesn’t have to return a boolean, it can pretty much be anything
1String carGoes = thing == "Car" ? "Vroom Vroom" : "Pew Pew Pew"