最近在学习flutter相关方面的知识,里面用到了Dart语言,于是写下这篇博客记录学习的一门过程。如果你有其他编程语言的经验(尤其是Java和JavaScript),可以很快的上手Dart语言,Dart 在设计时应该是同时借鉴了 Java 和 JavaScript,同时又引入了一些现代编程语言的特性,如空安全,除此之外还有一些独创的语法,比如级联操作符。总之,熟悉之后,你会发现 Dart 是一门非常有意思的编程语言 !
选择的编译工具为vscode,在vscode扩展中安装flutter和coder runner插件,之后便可以运行dart语言
例如:
void main(List<String> args) {
var name = "zhangsan";
print(name);
}
//输出为zhangsan
1.特殊关键字
变量是一个引用,在dart语言中具有“:万物皆对象的原则,即变量存储的都是对象的引用,或者说是它们指向对象。
1.1 不指定数据类型,即使用var关键字(类似与JavaScript)
var name = 'John';
1.2 指定数据类型
String name = 'John';
//因为有类型推导,所以两种实现效果一样,官方推荐在函数内的本地变量尽量使用var声明。
1.3 默认值
未初始化的变量默认值是 null。即使变量是数字类型默认值也是 null,因为在 Dart 中一切都是对象,数字类型也不例外。
int lineCount;//默认为空
assert(lineCount == null);//true
1.4 final和const关键字
使用过程中从来不会被修改的变量, 可以使用 final 或 const,而不是 var 或者其他类型,Final 变量的值只能被设置一次; Const 变量在编译时就已经固定 (Const 变量 是隐式 Final 的类型) 。最高级 final 变量或类变量在第一次使用时被初始化。
- Const关键字主要用于声明和创建常量。例如:
const bar = 1000000; // 压力单位 (dynes/cm2)
const double atm = 1.01325 * bar; // 标准气压
- final关键字
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
name = 'Alice'; // Error: 一个 final 变量只能被设置一次。
2. 常见数据类型
Dart 语言有以下的数据类型:
- Number
- String
- Boolean
- List (也被称为 Array)
- Map
- Set
- Rune (用于在字符串中表示 Unicode 字符)
- Symbol
2.1 Number
number有两种数据类型
- int(整型)
- double(双精度浮点数)
int 和 double 都是 num. 的亚类型。 num 类型包括基本运算 +, -, /, 和 *, 以及 abs(), ceil(), 和 floor(), 等函数方法。 (按位运算符,例如»,定义在 int 类中。) 如果 num 及其亚类型找不到你想要的方法, 尝试查找使用 dart:math 库。
double x = 1; 相当于 double z = 1.0.
int x = 0;
数据类型之间的相互转换(类似于Java语言)
// String -> int
var one = int.parse('1'); assert(one == 1); // String -> double
var onePointOne = double.parse('1.1'); assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString(); assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2); assert(piAsString == '3.14');
2.2 string数据类型
Dart 字符串是一组 UTF-16 单元序列。 字符串通过单引号或者双引号创建。
var s1 = 'Single quotes work well for string literals.';
字符串可以通过 ${expression} 的方式内嵌表达式。 如果表达式是一个标识符,则 {} 可以省略。 在 Dart 中通过调用就对象的 toString() 方法来得到对象相应的字符串。
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' == 'Dart has string interpolation, ' + 'which is very handy.'); //用$s来引用字符串s
assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == 'That deserves all caps. ' + 'STRING INTERPOLATION is very handy!');//引用字符串s并调整为大写字母
- 同时, == 运算符用来测试两个对象是否相等,可以使用 + 运算符来把多个字符串连接为一个。
2.3 Boolean数据类型
Dart使用bool类型标识布尔值。Dart只有字面量true和false。
// 检查空字符串。
var fullName = '';
assert(fullName.isEmpty);
2.4 List数据类型
Dart中的List字面量和Java的arry类型相类似,例如:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
// 往list里面添加数据
var test = [];
test.add(1);
2.5 set集合
在 Dart 中 Set 是一个元素唯一且无序的集合。 Dart 为 Set 提供了 Set 字面量和 Set 类型。下面为创建set集合的实例:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};//指定固定的几个元素
var elements = <String>{};//未指定大小
elements.add('fluorine'); elements.addAll(halogens);
assert(elements.length == 5);//获取长度
2.6 Map集合
通常来说, Map 是用来关联 keys 和 values 的对象。 keys 和 values 可以是任何类型的对象。在一个 Map 对象中一个 key 只能出现一次。 但是 value 可以出现多次。 Dart 中 Map 通过 Map 字面量 和 Map 类型来实现。
简单例子:
var gifts = {
// Key: Value
'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' };
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon', };
也可以使用Map构造函数来创建
var gifts = Map();
gifts['first'] = 'partridge'; //相当于添加元素
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
查找
var gifts = {'first': 'partridge'}; assert(gifts['first'] == 'partridge');//查找键值对
var gifts = {'first': 'partridge'};//查看key是否存在
assert(gifts['fifth'] == null);
3. 函数
3.1 函数声明
- 直接声明
// 直接声明
void printMsg() {
print("hello the world");
}
// 返回值与函数声明的类型要保持一致
String getNum(int num) {
return 'Age is $num';
}
void main(List<String> args) {
// 调用函数
print(getNum(18)); // Age 18
printMsg();
}
- 匿名函数
多数函数是有名字的, 比如 main() 和 printElement()。 也可以创建没有名字的函数,这种函数被称为 匿名函数, 有时候也被称为 lambda 或者 closure 。
var list = ['apples', 'bananas', 'oranges']; list.forEach((item) { print('${list.indexOf(item)}: $item'); });
// 如果函数只有一条语句, 可以使用箭头简写。
list.forEach( (item) => print('${list.indexOf(item)}: $item'));
- 立即执行函数
((int n) {
print(n);
}(55)); // 55
3.2 函数参数
- 必填参数
参数类型 参数名称 如:int age
// 必填参数
int getAge(int age) {
return age;
}
- 可选参数
1. 放在必填参数后面
2. 通过 中括号 包起来
3. 带默认值的可选参数
![[Pasted image 20230529162256.png]]
//解决方案一
String getNum(int age, [String name = "zhangsan"]) {
return 'Age is $age';
}
//解决方案二
String getNum1(int age, [dynamic name]) {
return 'Age is $age and his name is $name';
}
- 命名参数
1. 用 大括号 包起来
2. 调用函数时,命名参数的名称与声明函数中的名称保持一致
// 命名参数
String getScore(String subject, {double score = 0}) {
return '科目:$subject,分数:$score';
}
String math = getScore('数学', score: 123);//score与函数参数里面的名称一样
print(math); // 科目:数学,分数:123.0
3.3 main()函数
相当于Java的主函数,一个Java类必须要有主函数才能启动,任何应用都必须有一个顶级 main() 函数,作为应用服务的入口。 main() 函数返回值为空,参数为一个可选的 List<String>
。
void main(List<String> args) {
// 调用函数
}
4. 控制流程语句
dart语言的流程控制语句和Java语言相类似,主要有以下一些控制语句。
- if and else
- for loops
- while and do-while loops
- break and continue
- switch and case
- assert
4.1 if - else语句
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
4.2 for 循环语句
进行迭代操作
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
foreach迭代操作
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}
4.3 while和do-while语句
while循环在执行前判断执行条件
while (!isDone()) { doSomething(); }
do-while循环在执行后判断执行条件
do{
printLine();
}while(!atEndOfPage());
4.4 beak 和continue语句
使用break停止程序循环
while (true) {
if (shutDownRequested()) break; processIncomingRequests();
}
使用continue跳转到下一次迭代
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
}
4.5 switch与case
在 case 语句中,每个非空的 case 语句结尾需要跟一个 break 语句。 除 break 以外,还有可以使用 continue, throw,者 return。
当没有 case 语句匹配时,执行 default 代码:
var command = 'OPEN';
switch (command) {
case 'CLOSED':executeClosed();break;
case 'PENDING': executePending(); break;
case 'APPROVED': executeApproved(); break;
case 'DENIED': executeDenied(); break;
case 'OPEN': executeOpen(); break; default: executeUnknown();
}
4.6 assert语句
如果 assert 语句中的布尔条件为 false , 那么正常的程序执行流程会被中断。
// 确认变量值不为空。
assert(text != null); // 确认变量值小于100。
assert(number < 100); // 确认 URL 是否是 https 类型。
assert(urlString.startsWith('https'));
5.异常
Dart 代码可以抛出和捕获异常。 异常表示一些未知的错误情况。 如果异常没有被捕获, 则异常会抛出, 导致抛出异常的代码终止执行。
和 Java 有所不同, Dart 中的所有异常是非检查异常。 方法不会声明它们抛出的异常, 也不要求捕获任何异常。(就是如果没有主动抛出异常或者捕获异常,在编写代码时不会报错,但是会在运行的过程中报错)
Dart 提供了 Exception 和 Error 类型, 以及一些子类型。 当然也可以定义自己的异常类型。 但是,此外 Dart 程序可以抛出任何非 null 对象, 不仅限 Exception 和 Error 对象。
5.1 throw
下面是关于抛出或者 引发 异常的示例:
throw FormatException('Expected at least 1 section');
也可以抛出任意的对象
throw 'Out of llamas!';
5.2 try catch
捕获异常可以避免异常继续传递(除非重新抛出( rethrow )异常)。 可以通过捕获异常的机会来处理该异常:
try { breedMoreLlamas(); } on OutOfLlamasException { // 一个特殊的异常
buyMoreLlamas();
} on Exception catch (e) { // 其他任何异常,只捕捉指定类型的异常
print('Unknown exception: $e');
} catch (e) { // 没有指定的类型,处理所有异常
print('Something really unknown: $e'); }
5.3 finally
不管是否抛出异常, finally 中的代码都会被执行。 如果 catch 没有匹配到异常, 异常会在 finally 执行完成后,再次被抛出:
try { breedMoreLlamas(); } finally { // Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
//任何匹配的catch执行完成后都要执行finally语句:
try { breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls();
// Then clean up.
}
6. 类
6.1 实例变量
所有实例变量都生成隐式 getter 方法。
class Point {
num x = 0; // 声明示例变量 x,初始值为 0 。
num y = 0; // 声明示例变量 y,初始值为 0 。
num z = 0; // 声明示例变量 z,初始值为 0 。
}
void main(List<String> args) {
// 调用函数
var point = Point();
point.x = 4;
print(point.x == 4);// true
}
6.2 构造函数
通过创建一个与其类同名的函数来声明构造函数
在没有声明构造函数的情况下, Dart 会提供一个默认的构造函数。
class Point {
int x = 0, y = 0; //必须进行初始化
Point(num x, num y) {
this.x = x;
this.y = y;
}
//或者采用下面的方法
// Point(this.x, this.y);
}
6.3 继承
继承通过extends关键字实现,默认情况下,子类的构造函数会自动调用父类的默认构造函数(匿名,无参数)。
class Father {
String name = "zhangsan";
void sayName() {
print(name);
}
}
class Son extends Father {
void sayName() {
super.sayName();//调用父类方法
}
}
void main(List<String> args) {
var son = Son();
son.sayName(); // zhangsan
}
6.4 抽象类(与Java一样)
使用 abstract 修饰符来定义 抽象类 — 抽象类不能实例化。 抽象类通常用来定义接口,以及部分实现。 如果希望抽象类能够被实例化,那么可以通过定义一个 工厂构造函数 来实现。
抽象类通常具有 抽象方法。 下面是一个声明具有抽象方法的抽象类示例:
// 这个类被定义为抽象类,
// 所以不能被实例化。
abstract class AbstractContainer { // 定义构造行数,字段,方法...
void updateChildren(); // 抽象方法。
}
抽象类的一些特性:
- 抽象类不能实例化,只能单继承。
- 抽象类可以有抽象方法,只需声明,无需实现
- 有抽象方法的类一定是抽象类
- 抽象类的子类必须实现抽象类中的抽象方法,否则子类仍然是抽象类。(实现了就不是抽象类)