0 说明:
说明:该系列教程主要是为有一定语言基础 C/C++的程序员,快速学习一门新语言所采用的方法,属于在C/C++基础上扩展新语言只是体系的方式。
1 Dart语言简介
Dart亮相于2011年10月10日至12日在丹麦奥尔胡斯举行的GOTO大会,初衷是用于web、server、移动应用、物联网等领域的开发,语法跟C语言差不多、是面向对象、单继承的语言。
最开始是为解决JS的缺陷,但Node.js突然出现让JS可以在移动端跑起来,在这之后Dart就专注于跨平台了。后来搞出来一个移动开发框架Flutter,弯道超车进入移动端开发领域。在google的新系统Fuchsia 中大部分 UI 界面使用的是 Flutter,。dart的权重就直接上来了。
2 环境安装概要
针对于不同的操作系统,访问dart官网中页面-> 获取 Dart SDK | Dart,这里有现成的权威文档,linux、windows、mac都支持,按照步骤 执行即可。
为另外更好的体验,使用 vscode软件[ Visual Studio Code编辑器 ],无论哪个平台直接安装 dart 和 code runner插件即可。操作步骤各个平台都是一样的。code runner插件检索如下:
dart插件检索如下所示:
接下来就可以开始Dart语言的编写之旅了。来个 hello world 验证下,编写hello.dart文件
void main(){
print("hello world");
}
之后 点击右键,Run code,如下所示:
运行结果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
hello world
[Done] exited with code=0 in 0.305 seconds
接下来我们开始研究研究这玩意儿的语法(这里研究语法是以有C语言基础为前提的)。
3 基础语法-变量
3.1 变量基础知识
本质上和C语言很多地方类似,变量声明、定义、初始化,关键字等很多类似,但也有很多不同之处。这里更多是对和C语言不同的地方进行详细讲解。
@1 变量命名规则,Dart语言的标识符规则(和C/C++语言相差不大,标红处需注意):
- 标识符可以包括字符和数字。但是,标识符不能以数字开头。
- 除下划线(
_
)或美元符号($
)外,标识符不能包含特殊符号。 - 标识符不能是关键字。
- 它们必须是唯一的。
- 标识符区分大小写。
- 标识符不能包含空格。
3.2 数字型变量总结
C语言中 int float double 是基本数据类型,Dart中int double num(数字类型、可以是int / double中一种),而且还多了var弱类型,这玩意儿用起来省事儿不少。只不过类型名称上有些调整,这里用代码总结下:
void main() {
// 整型,整数值
var age1 = 2;
int age2 = 3;
// 浮点型
var salary1 = 44.44;
double salary2 = 55.55;
// num是int & double的父类,具体由dart自动推导
num age3 = 4;
num salary3 = 66.66;
print("$age1,$age2,$age3,$salary1,$salary2,$salary3");
}
运行后效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
2,3,4,66.66,66.66,66.66
[Done] exited with code=0 in 0.265 seconds
3.3 字符串类型变量总结
总体上看比C语言在使用上是简化很多了,这里使用代码进行总结。
@1 常用字符串API总结
代码实现如下:
void main() {
// 定义普通字符串
var city1 = 'Beijing';
var city2 = "Shanghai";
// 定义多行字符串
var str1 = '''
1111111111111111.
aaaaaaaaaaaaaaaa.
''';
var str2 = """
222222222222222.
bbbbbbbbbbbbbbb.
""";
//使用${expression}将表达式的值放在字符串中
var str3 = '33333 $city1 ccccc.';
//使用相邻的字符串文字或+运算符来连接字符串
var str4 = city1 + city2;
//在前面加上r来创建“原始”字符串:
var str5 = r'In a raw string, not even \n gets special treatment.';
print(city1);
print(city2);
print(str1);
print(str2);
print(str3);
print(str4);
print(str5);
}
运行效果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
Beijing
Shanghai
1111111111111111.
aaaaaaaaaaaaaaaa.
222222222222222.
bbbbbbbbbbbbbbb.
33333 Beijing ccccc.
BeijingShanghai
In a raw string, not even \n gets special treatment.
[Done] exited with code=0 in 0.27 seconds
@2 字符串和数字相互转换API总结
代码实现如下:
void main() {
// String -> int
var i1 = int.parse('1');
print(i1);
// String -> double
var i2 = double.parse('1.1');
print(i2);
// int -> String
String str1 = 10.toString();
print(str1);
// double -> String
String str2 = 3.1415926.toString();
print(str2);
}
运行效果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
1
1.1
10
3.1415926
[Done] exited with code=0 in 0.297 seconds
3.4 List /Set /Map 使用总结
@1 List常用API总结
List常用代码总结,实现如下:
void main() {
List<String> list = ['1', '2'];
print(list[0]); // 1
/* 添加: add、addAll */
list.add('3');
print(list); // [1, 2, 3]
print(list.first); // 1
print(list.last); // 3
print(list.reversed.toList()); // [3, 2, 1]
list.addAll(['4', '5']);
print(list); // [1, 2, 3, 4, 5]
print("---------------------------");
/*insert、insertAll */
list.insert(1, '-');
print(list); // [1, -, 2, 3, 4, 5]
list.insertAll(0, ['6', '7']); // 根据index索引位置插入多条
print(list); // [6, 7, 1, -, 2, 3, 4, 5]
print("---------------------------");
/*remove*/
list.remove('6');
print(list); // [7, 1, -, 2, 3, 4, 5]
list.removeAt(0); // 根据index索引,删除那条数据
print(list); // [1, -, 2, 3, 4, 5]
list.removeLast();
print(list); // [1, -, 2, 3, 4]
list.removeRange(1, 2); // 根据index索引区间,从start索引开始删,到end索引不删除
print(list); // [1, 2, 3, 4]
print("---------------------------");
/*update*/
list[0] = '8';
print(list); // [8, 2, 3, 4]
//根据index索引区间, 从start索引开始更新,到end索引结束更新(end索引位置不更新的);
//索引区间无论多少条数据,以新的条数为准;
list.replaceRange(1, 3, ['9', '0']);
print(list); // [8, 9, 0, 4]
print("---------------------------");
/*iterator*/
list.forEach((item) {
print(item);
});
print("---------------------------");
/*级联操作符*/
list
..add('x')
..add('*');
print(list);
print("---------------------------");
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
1
[1, 2, 3]
1
3
[3, 2, 1]
[1, 2, 3, 4, 5]
---------------------------
[1, -, 2, 3, 4, 5]
[6, 7, 1, -, 2, 3, 4, 5]
---------------------------
[7, 1, -, 2, 3, 4, 5]
[1, -, 2, 3, 4, 5]
[1, -, 2, 3, 4]
[1, 2, 3, 4]
---------------------------
[8, 2, 3, 4]
[8, 9, 0, 4]
---------------------------
8
9
0
4
---------------------------
[8, 9, 0, 4, x, *]
---------------------------
[Done] exited with code=0 in 0.306 seconds
@2 Set常用API总结
Set常用代码总结,实现如下:
void main() {
Set set = {'a', 'b', 'c'};
/*add、addAll*/
set.add('d'); //{a,b,c,d}
print(set);
set.add('a'); //集合特性:重复元素 不会2次添加 {a,b,c,d}
print(set);
set.addAll(['e', 'f', 'g', 'h']); //{a,b,c,d,e,f,g,h}
print(set);
print(set.first); //a
print(set.last); // h
print(set.length); //8
print("--------------------------------------------------");
/*remove removeAll clear*/
set.remove('g'); //{a,b,c,d,e,f,h}
set.removeAll(['a', 'c', '2']); //对于Set不存在的元素会直接略过//{b,d,e,f,g,h}
print(set);
Set set2 = Set.from(set); //{b,d,e,f,g,h}
print(set2);
set2.clear(); //{}
print(set2);
print("--------------------------------------------------");
/*query contains*/
print(set.contains('a')); //false
print(set.contains('b')); //true
print(set.containsAll(['a', 'b'])); //false 表示同时包含a和b
print(set.elementAt(0)); //b
print("--------------------------------------------------");
/*iterate*/
/*i1*/
for (var item in set) {
print(item);
}
/*i2*/
set.toList().forEach((item) {
print(item);
});
print("--------------------------------------------------");
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
{a, b, c, d}
{a, b, c, d}
{a, b, c, d, e, f, g, h}
a
h
8
--------------------------------------------------
{b, d, e, f, h}
{b, d, e, f, h}
{}
--------------------------------------------------
false
true
false
b
--------------------------------------------------
b
d
e
f
h
b
d
e
f
h
--------------------------------------------------
[Done] exited with code=0 in 0.285 seconds
@3 Map常用API总结
Map常用代码总结,实现如下:
void main() {
Map map = {'name': 'zhangsan', 'age': 23};
print(map['name']); //zhangsan
/*add*/
map.addAll({'address': 'Beijing'});
map.addAll({'sex': 'Male'});
print(map); // {name: zhangsan, age: 23, address: Beijing ,sex: Male}
print(map.length); // 4
print(map.keys.toList()); //[name, age, address ,sex]
print(map.values.toList()); //[zhangsan, 23, Beijing, Male]
print("--------------------------------------------------");
/*iterate*/
map.forEach((key, value) {
print('key=$key value=$value');
/* key=name value=Zhangsan
key=age value=23
key=address value=Beijing
key=sex value=Male
*/
});
print("--------------------------------------------------");
/*update*/
map['name'] = 'Lisi';
print(map); //{name: Lisi, age: 23, address: Beijing ,sex: Male}
/*remove*/
print(map.isNotEmpty); // true
map.remove('name');
print(map); // {age: 23, address: Beijing}
map.clear();
print(map); // {}
print(map.isEmpty); // true
print("--------------------------------------------------");
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
zhangsan
{name: zhangsan, age: 23, address: Beijing, sex: Male}
4
[name, age, address, sex]
[zhangsan, 23, Beijing, Male]
--------------------------------------------------
key=name value=zhangsan
key=age value=23
key=address value=Beijing
key=sex value=Male
--------------------------------------------------
{name: Lisi, age: 23, address: Beijing, sex: Male}
true
{age: 23, address: Beijing, sex: Male}
{}
true
--------------------------------------------------
[Done] exited with code=0 in 0.277 seconds
3.5 Rune使用总结
Rune是用来表示字符串中的UTF-32编码字符。因为 Dart 字符串是基于一系列 UTF-16 编码单元, 因此要在字符串中表示32位Unicode值需要特殊的语法支持,如下所示:
void main() {
// Rune是UTF-32编码的特殊字符串。可以通过文字转换成符号表情或者代表特定的文字。
Runes emoji =
Runes('\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(String.fromCharCodes(emoji));
}
这玩意儿的用途感觉就是支持这种表情包 / 特殊字符。运行效果如下所示:
Running] dart "/data/AGS/Dart/Project/hello.dart"
♥ 😅 😎 👻 🖖 👍
[Done] exited with code=0 in 0.267 seconds
3.6 变量关键知识点总结
@1 final和const
两者都是声明不可更改变量,变量只能设置一次。但final不一定在声明时赋值,而const必须在定义的时候初始化。可以理解为const更加严格,这里使用代码清晰的描述下两者之间的区别,如下:
void main() {
//final vs const
final d11; //正确,运行时有确定的值
d11 = DateTime.now();
print(d11);
final d12 = DateTime.now(); //正确,运行时有确定的值
print(d12);
const d22 = DateTime.now(); //报错,抛出异常; 需要编译时有确定的值
}
可以看出final可以在声明时候不初始化,运行时根据需要只初始化一次,但const不行,必须最开始就初始化。
@2 Dart语言中的弱语言关键字var、Object、dynamic的区别
Dart是强类型语言,但也支持一些弱类型,Dart 中弱类型有var
, Object
以及dynamic,他们的区别如下所示:
- var 初始可定义, 如果有初始值,那么其类型将会被锁定,定义之后不可改变类型。
- Object 赋值后仍可改变变量类型。编译阶段检查类型。
- dynamic 赋值后仍可改变变量类型。编译阶段不检查类型。
这里使用代码清晰的描述下后两者之间的区别,如下:
void main() {
// dynamic vs Object
dynamic a = "xyz";
a = 2;
int b = a + 3;
print(b); // 5
Object c = "abc";
c = 2;
int d = c + 3;
print(d);
}
运行后效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
hello.dart:10:13: Error: The operator '+' isn't defined for the class 'Object'.
- 'Object' is from 'dart:core'.
Try correcting the operator to an existing operator, or defining a '+' operator.
int d = c + 3; // 报错,抛出异常
^
[Done] exited with code=254 in 0.255 seconds
注意:所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象。Object 数据类型是确定的 , 因此不能调用 Object 类中不存在的方法。而dynamic可以根据自己需要使用任何数据类型的方法。
@3 类型判断 is关键字
与C/C++相比,多了这个类型判断的功能,目测很实用,也很简单,用法如下:
void main() {
var a = 198;
print(a is dynamic); // true
print(a is num); // true
print(a is int); // true
print(a is String); // false
}
4 运算符(??= 运算符 和 ??运算符支持)
运算符部分基本和C/C++一致,包括关系运算符、逻辑运算符号、条件表达式等。因此这里主要关注不一样的地方即??= 运算符 和 ??运算符。它们表示 如果变量之前初始化过则使用原来的值,如果未初始化过则使用该值,测试代码如下:
void main() {
//--------??=--------------
//初始化过
var a = 198;
a ??= 201;
print(a);
//未初始化过
var b;
b ??= 202;
print(b);
//--------??--------------
//未初始化过
var c;
var d = c ?? 10;
print(d); // 输出10
//初始化过
var e = 20;
var f = e ?? 10;
print(f); // 输出20
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
hello.dart:5:3: Warning: Operand of null-aware operation '??=' has type 'int' which excludes null.
a ??= 201;
^
hello.dart:21:11: Warning: Operand of null-aware operation '??' has type 'int' which excludes null.
var f = e ?? 10;
^
198
202
10
20
[Done] exited with code=0 in 0.284 seconds
5 函数
函数实现方面在C语言基础上扩充了不少东西,宗旨就是为了方便好用。函数中定义函数、箭头函数、匿名函数、自执行方法、闭包等,这里逐一说明。
5.1 函数中的函数
在Dart语言中,可以将函数定义在函数中,不再像C/C++那样,只能在函数外定义函数,这一点更加灵活一些,代码如下所示:
void main() {
//主函数中定义函数f1
String f1(int i) {
print("f1:$i");
//函数f1中定义函数f2
String f2(String str) {
return "f2:$str";
}
return "f1" + f2("test");
}
//输出结果
print(f1(6));
}
运行效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
f1:6
f1f2:test
[Done] exited with code=0 in 0.269 seconds
5.2 箭头函数
箭头函数中,=>用于分离函数声明和函数体。相关代码如下所示:
void main() {
// 普通函数写法
void printInt1(int i) {
print(i);
}
// 箭头函数写法
void printInt2(int i) => print(i);
printInt1(1);
printInt2(2);
print("--------------------------");
List list = [2, 4, 6, 8, 10];
//普通写法
var newList = list.map((e) {
return e > 5 ? 5 : e;
});
print(newList.toList());
//箭头函数写法
var newList1 = list.map((e) => e > 5 ? 5 : e);
print(newList1.toList());
}
运行效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
1
2
--------------------------
[2, 4, 5, 5, 5]
[2, 4, 5, 5, 5]
[Done] exited with code=0 in 0.273 seconds
5.3 匿名函数
匿名方法一般用于变量赋值和参数传递,代码如下所示:
void main() {
//匿名方法 变量声明
var f = (int i) {
//定义了一个变量f(),后面是匿名方法,可以传递参数,也可以没有参数
print("匿名方法$i");
};
f(5);
String getInfo(f2(int i)) {
return f2(6);
}
//打印:匿名函数传递参数
print(getInfo((int i) {
return "f3=$i";
}));
}
运行效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
匿名方法5
f3=6
[Done] exited with code=0 in 0.282 seconds
5.4 自执行方法
即指不需主动调用,程序启动时会自动执行该段代码,代码如下所示:
void main() {
print("1");
//自执行代码 开始
(() {
print("自执行代码");
})();
//自执行代码 结束
print("2");
}
运行效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
1
自执行代码
2
[Done] exited with code=0 in 0.952 seconds
注意:自执行代码只是 执行到对应位置会自动执行,并不是程序最开始时立刻执行。
5.5 函数传参
Dart语言中函数参数这里用[ ]包含的参数为可选参数,可以传递,也可以不传递,可以赋值默认值,也可以不赋值,同时还可以将函数本身作为参数传递,相关代码如下所示:
void main() {
//参数可选
String getInfo(String name, [int? age, String? sex]) {
return "name:$name;age:$age;sex:$sex";
}
//参数可选,且有默认值
String getInfo2(String name, [int? age = 10, String? sex = "female"]) {
return "name:$name;age:$age;sex:$sex";
}
String getInfo3() {
return "name:zhangsan;age:18";
}
//函数方法可以作为参数被传递
String method1(f()) {
return f();
}
print(getInfo("name")); // 输出name:name;age:null;sex:null
print(getInfo("name", 8)); //输出name:name;age:8;sex:null
print("------------------------------------------");
print(getInfo2("name")); // 输出name:name;age:null;sex:null
print(getInfo2("name", 8)); //输出name:name;age:8;sex:null
print("------------------------------------------");
print(method1(getInfo3));
}
运行效果如下:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
name:name;age:null;sex:null
name:name;age:8;sex:null
------------------------------------------
name:name;age:10;sex:female
name:name;age:8;sex:female
------------------------------------------
name:zhangsan;age:18
[Done] exited with code=0 in 0.297 seconds
5.6 闭包
闭包概念:对于全局变量常驻内存且全局均受影响,对于局部变量又无法做到常驻内存,我们需要一种常驻内存又不影响全局的模式,因此就有了闭包,代码实现如下:
void main() {
//闭包
f() {
int count = 0;
void printf() {
count++;
print(count);
}
//特别注意 这里的写法:直接返回函数,不带括号
return printf;
}
var a = f();
a();
a();
a();
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
1
2
3
[Done] exited with code=0 in 0.278 seconds
5.7 typedef关键字
typedef 在C/C++中主要为现有类型创建别名,定义易于记忆的类型名typedef 还可以掩饰复合类型,如指针和数组,比如:
typedef int size;
size array[4];//此时size相当于int
typedef int *(*pFun)(int, char*); //此时定义了一个函数指针,类型就是包含参数为(int, char*),返回值为int *的函数。
在Dart语言中 typedef的用法是类似的,相关代码实现如下:
typedef void Operate(int num1, int num2);
void main() {
Addition(int num1, int num2) {
print("Addition: ${(num1)} + ${(num2)} = ${(num1 + num2)}");
}
Subtraction(int num1, int num2) {
print("Subtraction: ${(num1)} - ${(num2)} = ${(num1 - num2)}");
}
Operate op;
op = Addition;
op(3, 5); //8
op = Subtraction;
op(5, 3); //2
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
Addition: 3 + 5 = 8
Subtraction: 5 - 3 = 2
[Done] exited with code=0 in 0.278 seconds
6 顺序、选择、循环基本语句(switch case字符串支持)
关于顺序、选择循环语句这些与C/C++基本一致。这里主要看不一样地方。条件表达式中switch case支持字符串选项。使用代码描述,如下所示:
void main() {
var sex = "male";
switch(sex){
case "male" :
print("male");
break;
case "female":
print("female");
break;
default:
print("param error");
break;
}
}
运行结果如下所示:
[Running] dart "/data/AGS/Dart/Project/hello.dart"
male
[Done] exited with code=0 in 0.301 seconds