Dart language tutorial
Code Standards
Almost identical to C/C++.
- Extension: Dart language files end with
.dart. - Entry point: The entry method of a Dart file is the
mainmethod. - Semicolon: Most statements in Dart files need to end with a semicolon, but typically no semicolon is added after
{ }.
Dart's variables
This section is highly similar to C/C++.
String Type - String
Basically similar to std::string in C/C++.
Basic Usage:
- Keyword: String
- Grammar:
String 属性名 = ‘文本内容’; - Features: Supports double or single quotation marks, as well as concatenation and template strings.
Advanced Usage:
- Grammar:
String 属性名 = ‘文本内容$变量名’;orString 变量名 = ‘文本内容${变量名}’; - Note: When the content in the template is an expression, use
${}. Whether it's an expression or a variable,${}is recommended. Try to avoid using$变量名whenever possible.
void main()
{
String name = 'Alice';
print(name); // Output: Alice
name = 'Bob';
print(name); // Output: Bob
String greeting = 'Hello, ${name}?$name!';
print(greeting); // Output: Hello, Bob?Bob!
String when = 'it is ${DateTime.now()},now';
print(when); // Output: it is 2026-02-16 14:46:17.818262,now
}
Numeric Types - int/double/num
It is basically similar to C/C++, int, and double.
Basic Syntax
- Scenario: When we need to describe a numeric type, we use int/num/double.
- Difference: int - integer number, double - decimal number, num - can be either integer or decimal.
- Grammar:
int/num/double 属性名 = 数值;
void main()
{
int age = 23;
print(age); // Output: 23
age = 24;
print(age); // Output: 24
double height = 1.78;
print(height); // Output: 1.78
height = 1.80;
print(height); // Output: 1.8
num weight = 90.5;
print(weight); // Output: 90.5
weight = 76;
print(weight); // Output: 76
}
The essential differences between the three:
num
├── int
└── double
- 👉 num is the parent class
- 👉
intanddoubleare subclasses
Direct Assignment Rule Summary Table:
| Assignment direction | Can it be assigned directly? | Explanation |
|---|---|---|
| int → num | ✅ Yes | The subclass gives to the parent class. |
| double → num | ✅ Yes | The subclass gives to the parent class. |
| num → int | ❌ No | It might be double. |
| num → double | ❌ No | It might be int |
| int → double | ❌ No | Dart does not automatically convert |
| double → int | ❌ No | will lose decimals |
| int → int | ✅ | |
| double → double | ✅ | |
| num → num | ✅ |
Although direct assignment is not possible, you can convert the value first and then assign it. This can be achieved using methods such as toInt() and toDouble(), for example:
void main()
{
int a = 10;
print(a); // Output: 10
double b = 3.14;
print(b); // Output: 3.14
// double赋值给double
double c = b;
print(c); // Output: 3.14
// int赋值给double
b = a.toDouble();
print(b); // Output: 10.0
num d = 5.6;
print(d); // Output: 5.6
// num赋值给int
a = d.toInt();
print(a); // Output: 5
}
Boolean type - bool
Basically similar to bool in C/C++.
- Scenario: When we need a property to represent whether something is currently true or false, we must use the
boolkeyword to declare it. - Requirement: Declare whether you have completed the assignment.
- Grammar:
bool 属性名 = true/false;
void main()
{
bool isFinishWork = false;
print('我的工作完成状态为:$isFinishWork'); //Output: 我的工作完成状态为:false
isFinishWork = true;
print('我的工作完成状态为:$isFinishWork'); //Output: 我的工作完成状态为:true
}
List type - List
List
Basically similar to the STL vector std::vector in C/C++. (Note: it is not like std::list.)
And std::vector we often use it as 不定长数组, so when you don't understand std::vector, you can think of it as an advanced 数组.
This section definitely won't cover all the uses of List, but it will cover most of the commonly used ones. If you forget, you can always look up the documentation—there's no need to memorize every single usage. The ones you use frequently will naturally stick. For now, just go through it once and know that such a thing exists.
Basic Usage:
- Scenario: When a variable needs to store multiple values, you can use the List type.
- Requirement: A class of students is stored using a List, supporting student search, addition, deletion, and iteration.
- Syntax: List attribute_name = 'Student1', 'Student2';
Common Usage 1:
- Add -
add(内容)at the end. - Add a list at the end:
addAll(列表)- Delete the first
-that satisfies the content. - Delete the last -
removeLast() - Delete data within the index range -
removeRange(start,end)Note: end is not included in the deletion range.
Common Usage 2:
Below are a few methods and properties. If you've studied object-oriented programming, you'll know what they are. If not, I'll give a quick explanation:
类-class的声明与定义
对象-class类型的实例,(不好理解也可以理解为class类型的变量)
方法-class里的函数
属性-class里的变量
- Loop (Method) -
forEach((item) {}); - Do all conditions meet (method) -
every((item) { return 布尔值 }); - Filter out data that meets the criteria (method) -
where((item) { return 布尔值 }); - Length of a List (Property) -
length - The last element (attribute) -
last - First element (attribute) -
first - Is empty (attribute) -
isEmpty
void main(List<String> args)
{
List students = ["张三", "李四", "王五"];
print(students); // Output: [张三, 李四, 王五]
students.add("新同学"); // 在尾部进行添加
print(students); // Output: [张三, 李四, 王五, 新同学]s
students.addAll(["新来的同学1", "新来的同学2"]); // 在尾部添加一个列表
print(students); // Output: [张三, 李四, 王五, 新同学, 新来的同学1, 新来的同学2]
students.add("新同学"); // 在尾部进行添加
print(students); // Output: [张三, 李四, 王五, 新同学, 新来的同学1, 新来的同学2, 新同学]
students.remove("新同学"); // 删除满足内容的第一个
print(students); // Output: [张三, 李四, 王五, 新来的同学1, 新来的同学2, 新同学]
// 删除最后一个同学
students.removeLast(); // 删除最后一个
print(students); // Output: [张三, 李四, 王五, 新来的同学1, 新来的同学2]
// 删除前两个同学
// start开始的索引 end结束的索引-不包含在删除范围内
students.removeRange(0, 2);
print(students); // Output: [王五, 新来的同学1, 新来的同学2]
// forEach针对每个列表每个数据进行操作
students.forEach((item)
{
// 书写逻辑
print(item); // Output: 王五
// 新来的同学1
// 新来的同学2
});
// 是不是所有的同学都以新为开头
bool isAllStartWithNew = students.every((item)
{
return item.toString().startsWith("新"); // 返回一个条件
});
print(isAllStartWithNew); // Output: false (因为王五不以新开头,需要满足所有的同学都以新开头才会返回true)
// 筛选出所有的以新开头的同学呢
List newStudents = students.where((item)
{
return item.toString().startsWith("新");
}).toList();
print(newStudents); // Output: [新来的同学1, 新来的同学2]
// List常用的一些属性 方法() .属性
// 列表的长度
print(students.length); // Output: 3
// 列表的第一个
print(students.first); // Output: 王五
// 列表的最后一个
print(students.last); // Output: 新来的同学2
// 列表是否是空的
print(students.isEmpty); // Output: false (因为列表中有数据)
}
Main function entry parameters
In addition to the code above, you can see that void main(List<String> args) already has parameters. This is actually similar to int main(int argc, char* argv[]) in C/C++.
| Compare points | C/C++ | Dart |
|---|---|---|
| Number of parameters | argc | args.length |
| Parameter array | argv[] | List<String> |
| Does it include the program name? | ✅ argv0 is the program name | ❌ Not included |
| Type safety | ❌ char* | ✅ String |
| Memory management | Manual | automatic |
For example
dart run app.dart hello world
At this moment
args[0] = "hello"
args[1] = "world"
Dictionary Type - Map
Similar to C++'s std::map.
Basic Usage:
- A key corresponds to a value.
- Syntax 1: Map property name = { key: value };
- Grammar 2:
字典[key] 可以取值和赋值
Common Usage:
- Loop -
forEach - When adding a dictionary-
addAll - Whether a certain key is included -
containsKey - Delete a key-
remove - Clear-
clear
void main(List<String> args)
{
Map transMap = {"lunch": '午饭', "morning": "早上", "hello": '你好'};
print(transMap);
// 通过英文找到对应中文的描述
print(transMap["morning"]);
transMap["hello"] = "你非常好";
print(transMap["hello"]);
// 字典里面有很多对应关系
transMap.forEach((key, value) {
print("$key,$value");
});
// addAll 给当前字典添加一个字典
transMap.addAll({"fine": "非常好"});
print(transMap);
// containesKey判断字典中是否包含某个key
print(transMap.containsKey("fine"));
transMap.remove("fine");
print(transMap);
// 清空字典
transMap.clear();
print(transMap);
}
dynamic type
Similar to C++'s std::any
- Definition: In the Dart language,
dynamicis used to declare a dynamic type. - Feature: Allows variables to freely change type at runtime, while bypassing compile-time static checks.
- Syntax 1:
dynamic 属性名 = 值;
void main(List<String> args)
{
// dynamic 可以动态的改变类型
dynamic name = "张三";
print(name);
name = 123;
print(name);
}
Only use dynamic if you are 100% certain that what you are writing is correct; otherwise, avoid it, as it may introduce many errors.
Auto-deduced type - var
Similar to C/C++'s auto.
This keyword can automatically deduce the type of a variable.
- Keywords: var
- Grammar:
var 变量名 = 值/表达式; - Note: The type of a variable declared with
varis determined after its first assignment and cannot be reassigned to a different type.
void main(List<String> args)
{
var name = '张三';
print(name); // Output: 张三
name = '李四';
print(name); // Output: 李四
var age = 30;
print(age); // Output: 30
var isStudent = true;
print(isStudent); // Output: true
var height = 1.75;
print(height); // Output: 1.75
}
Dynamic types in Dart: The difference between dynamic and `var:
- dynamic: Types can be freely changed at runtime with no compile-time checks; methods and properties are called directly.
- var: Infers the type based on the initial value. Once the type is determined, it is fixed and subject to compile-time checks. Only the inferred properties and methods are available.
Constant Declaration - const/final
const
Similar to C++'s constexpr.
- Keyword: const
- Syntax:
const propertyName = value/expression; - Feature:
constis determined before code compilation and does not allow variables in expressions; it must be a constant or a fixed value.
void main(List<String> args)
{
const int a = 10;
const double b = 3.14;
const String c = "Hello, Dart!";
print("Value of a: ${a}"); // Output: Value of a: 10
print("Value of b: ${b}"); // Output: Value of b: 3.14
print("Value of c: ${c}"); // Output: Value of c: Hello, Dart!
}
final
Similar to C++'s const.
- Keyword: final
- Syntax:
final propertyName = value/expression; - Feature: A final variable is initialized at runtime, and its value cannot be changed once set.
void main(List<String> args)
{
final time = DateTime.now();
print('Current time: $time'); // Current time: 2026-02-16 20:53:53.045010
}
- Variable: When you need to store a changing piece of data, you must use
varto declare the variable. - Compile-time constant: When you need to store an unchanging piece of data that is determined at compile time, you must declare the constant using
const. - Runtime constant: When you need to store an unchanging piece of data that is only determined at runtime, you must declare the constant using
final.
| concept | Dart | C++ | Is it a compile-time constant | Can it be determined at runtime? | Is the object immutable? |
|---|---|---|---|---|---|
| Assigned only once | final | const | ❌ | ✅ | ❌ |
| Compile-time constant | const | constexpr | ✅ | ❌ | ✅ (Dart is stronger) |
| Read-only variable | not completely equivalent | const | ❌ | ✅ | ❌ |
Null safety mechanism
- Definition: In the Dart language, runtime null pointer errors are exposed early through compile-time static checks.
- Feature: Moves null pointer exceptions from runtime to compile time, reducing production crashes.
Common Null Safety Operators
|operator|symbol|effect|Here is the translation of the provided Simplified Chinese Markdown fragment into natural American English, following all specified rules.
Example|
| :--- | :--- | :--------------------- | :------------------------------------------ |
|Nullable types|?|Declare a nullable variable|String? → Allows String or null|
|Secure Access|?.|Skip the operation when the object is null and return null.|user?.name → returns null if user is null|
|Non-null assertion|!.|The developer guarantees that the variable is not null (otherwise it will crash at runtime).|name!.length → assert name is not empty|
|null coalescing|??|Returns the default value on the right when the left side is null.|name ?? "Guest" → returns "Guest" when name is null|
|Nullish coalescing assignment|??=|Assign a value only when the variable is null.|name ??= "Guest"|