Dart学习

博主最近很是放松。作为应届毕业生,我的毕业论文初稿已经写完了,也找到了满意的工作。人在不学习的时候就会产生无限的学习欲望,我真的是太想进步了。最近对 OASX的翻译项目上心,项目使用的语言是 Flutter,所以想学习一下。Dart 是一种面向对象的编程语言,由 Google 开发,用于构建高性能的 Web 应用程序、移动应用程序和服务器端应用程序。Dart 语言结合了静态类型检查、动态类型检查和即时编译的特性,能够提供更高效、更安全的开发体验。
1. Dart 环境安装
1.1 Dart SDK 安装
Flutter SDK 是包含 Dart SDK 的,直接安装 Flutter SDK 即可。我这里的开发工具为 VS Code 和 Android Studio。Flutter SDK 下载地址:
1 | https://docs.flutter.dev/get-started/install |
根据自己的系统下载 Flutter 的安装包:
下拉找到 install the Flutter SDK
然后下载安装包(科学上网下载更快哦):
下载完成后进行解压
进行环境变量配置,首先点击 系统变量
下面的 新建
按钮。在系统变量里新建一个选项,变量名为 FLUTTER_HOME
变量,变量值为 Flutter SDK 的解压目录。之后,在 系统变量
中找到 Path
选项,然后点击 编辑
按钮,在 Path
选项配置右侧点击 新建
,添加 %FLUTTER_HOME%\bin
,然后点击确定按钮。
在 CMD
命令行中输入以下两个命令查看配置是否成功(可能重启重启电脑,环境变量配置才能生效)出现版本即为配置成功
1 | # 查看flutter版本 |
1.2 VS Code 配置
VS Code 只需要安装两个插件即可,分别为 Dart
和 Code Runner
。
1.3 Hello Word
经典 Hello World
。我没有敲错,难道说我真的是编程天才?
1 | void main(List<String> args) |
(1)上面的 main
是一个函数,也是程序的入口函数,程序启动,会从这里开始执行;
(2)void
表示函数是没有返回值的,返回值可以缺省;
(3)List<String> args
表示函数的参数,main 函数的参数可以省略;
(4)print("Hello World");
使用打印函数将字符串 “Hello World” 打印到屏幕上。
注:每行语句必须使用分号结尾。根据上面描述的 main
函数的参数可以省略,所以上述程序还可以写为:
1 | main() |
2. 基础语法
2.1 数据类型
Dart 是一种强类型语言,以下是 Dart 中支持的数据类型:
- 数值型:int(整数)、double(浮点数)
- 布尔型:bool
- 字符串:String
- 列表:List
- 集合:Set
- 映射:Map
下面先介绍一下 数字 、字符串、布尔值,列表、集合、映射 会在介绍集合时进行学习。
什么是强类型语言?
DeepSeek 回答
强类型语言是指在编程中对数据类型有严格要求的语言。这类语言要求变量必须在声明时指定类型,并且在运行时严格检查类型,不允许不同类型的数据随意转换或操作。例如,C#和 Java 都是强类型语言。这种严格的类型管理有助于减少运行时错误,提高代码的可靠性和可维护性。2.1.1 数值
和数学中的一致,有整数和小数。例如:2,123,-12,12.13,-10.24。
2.1.2 字符串
字符串(string),又称文本,是由任意数量的字符如中文、英文、各类符号、数字等组成。特别的,在 Dart 中,支持单引号、双引号、三引号,和 Python 是一模一样的。
1 | '123' //这是一个字符串,不是数字 |
2.1.3 布尔
布尔值只有两个,即 true
和 false
,也就是真和假。
2.2 注释
2.2.1 单行注释
单行注释一般用于对一行或一小部分代码进行解释,单行注释以 //
开头,//
号右边为注释内容。同时,// 号和注释内容一般建议以一个空格隔开,这是代码规范,建议大家遵守。
1 | // 打印Hello World |
2.2.2 多行注释
多行注释是以 /* */
括起来,中间的内容为注释内容,注释内容可以换行。多行注释一般对:类、方法进行解释,类和方法后面我们再学习。
1 | /* |
2.3 变量和常量
变量是在程序运行的时候存储数据用的,可以想象变量为一个盒子。整数、浮点数(小数)、字符串都可以放在变量中。
2.3.1 变量的定义
分别使用 String
来定义字符串、int
来定义整数、double
来定义浮点数。
1 | main(){ |
2.3.2 var 定义变量
在 Dart 中可以使用 var
来替代具体类型的声明,会自动推导变量的类型。
1 | main(){ |
注:var name = "zhangsan;"
已经确定了变量 name 的数据类型为字符串,无法使用 name=123;
进行其他类型数据赋值。
2.3.3 常量
变量的值是可以变的,就像上面我们定义了变量,后面可以修改它的值。与之相对的,常量的值不能改变的。
在 Dart 中,使用 final
或 const
关键字来定义常量。两者的区别在于:
final
关键字定义的常量是在第一次使用时初始化的,初始化后不可改变;const
关键字定义的常量在编译时就已经被初始化了,永远不会改变。
1 | main() { |
使用 const 定义的常量也可以使用 final 来定义,但是使用 const
定义,这有助于优化性能和节省内存。另外需要注意的是,常量和变量的类型可以显式指定,也可以通过类型推断来自动推断。
1 | // 使用const关键字定义常量,并显式指定类型为 int |
2.3.4 dynamic
在使用 var
定义变量的时候,无法给一个 String
类型的变量赋值其他类型数据,但是 dynamic
类型的变量可以在运行时动态地改变其类型,而不需要在编译时指定类型。
dynamic
是一种特殊的类型,它可以表示任何类型的值。
1 | dynamic variable = "Hello World"; |
上面,定义了一个名为 variable
的变量,并将其初始化为字符串 "Hello World"
。然后,我们将其值更改为整数 42
,最后再将其值更改为布尔值 true
。这些更改都是在运行时进行的,而不需要在编译时指定类型。
注意:由于 dynamic
类型可以表示任何类型的值,因此它可能会导致一些意想不到的错误,尤其是在代码变得复杂时。因此,建议尽可能使用更具体的类型来声明变量。
2.4 数据类型与转换
2.4.1 获取数据类型
通过 变量.runtimeType
可以获取变量当前的类型。
1 | main(){ |
使用 dynamic
定义的变量,数据类型是可以变化的。
2.4.2 数据类型判断
通过 is
关键字,可以判断当前变量的类型。
1 | import 'dart:ffi'; |
is
结果返回的是一个 bool
值。
2.4.3 int 与 double 转换
-
int 转换为 double(一般好像用不到 int 转 double)
1
2
3int i = 3;
double d = i.toDouble();
print(d); // 输出:3 -
double 转 int(小数点后忽略,向下取整)
1
2
3double d = 3.14;
int i = d.toInt(d);
print(i); // 输出:3可以使用 round()方法,在取整时,四舍五入:
1
2
3double d = 3.6;
int i = d.round();
print(i); // 输出:4
2.4.4 Srting 与数字相互转换
-
数字转换为 String
1
2
3int number = 42;
String str = number.toString();
print(str); // 输出:42 -
String 转换为数字(使用
parse()
函数将字符串转换为数字)1
2
3
4
5
6
7String str = '42';
int num1 = int.parse(str);
print(num1); // 输出:42
double num2 = double.parse(str);
print(num2); // 输出:42.0需要注意的是,如果字符串不能被解析为数字,则会抛出一个异常,导致程序终止运行。因此,建议在使用
parse()
函数时使用try-catch
语句来处理可能的异常。(异常处理后面再学习)。也可以使用tryParse()
函数来将字符串转换为数字,不会抛出异常。1
2
3
4
5void main() {
var str = "hello";
var number = int.tryParse(str);
print(number); // 输出:null
}转换不成功,返回 null,不会抛出异常。但是,需要注意
tryParse(参数)
方法的参数不能为null
,转换会报错。
2.4.5 dynamic 转其他类型
将 dynamic
转换为 int、double或String
,直接赋值即可。
1 | dynamic varable = 42; |
类型相同才能转换,否则会报错。
2.5 标识符
标识符就是名字,例如变量的名字、方法的名字、类的名字。起名字肯定会有限制,肯定不能 张 Three 这样起名字,所以标识符也有限制。
2.5.1 标识符命名规则
标识符需要遵守一下规则:
-
只能是英文、数字、下划线,其他任何内容都不允许;
-
不能使用数字开头,可以英文或下划线开头;
1
2
3
4
5
6
7
8
9a; // 可以
a_b; // 可以
_a; // 可以
a1; // 可以
a_b_a;// 可以
1; // 错误
1_; // 错误
1_a; // 错误 -
大小写敏感,大小写不同是不同的标识符;
1
2String name = "zhangsan";
String Name = "lisi"; // 和name是不同的标识符 -
不能使用关键字,关键字就是 Dart 中保留的一些单词,有特殊的用途,不能被用作标识符;
abstract as assert async await break case catch class const continue convariant sync deferred do dynamic else default export extend extension external enum false final finally for factory get hide if implements Function in interface is late import mixin new null on library out part rethrow retrun operator show static super switch set this throw true try typedef var void while with yield 这么多怎么记?不用记!不用记!不用记!后面每个关键字都会学到,自然知道每个关键字是做什么用的,不用记!
2.5.2 变量命名规范
定义变量名为了优雅、统一、规范,我们在定义变量名时,还应该遵守以下规范,虽然你不遵守,没人开枪打死你,但是建议你遵守。
-
见名知意
看见一个变量名,就知道这个变量名的作用。
1
2
3String a = "zhangsan"; // 看到a,鬼知道a是干嘛的
String name = "zhangsan"; // 看到name,就知道这是个名字,简单明了
String peronName = "zhangsan"; // 在确保明了的前提下,尽量减少长度,这个有点不够简洁 -
类名使用首字母大写的驼峰规则
1
2class BankAccount {}
class ShoppingCartItem {} -
变量使用首字母小写的驼峰规则
1
2String name;
String accountNumber;
2.6 字符串扩展
2.6.1 字符串定义方式
之前通过使用双引号 " 来定义字符串,但其实字符串有 3 种不同的定义方式:
-
双引号定义法
1
var text1 = "我是一个字符串";
-
单引号定义法
1
var text2 = '我是一个字符串';
-
三引号定义法(可以进行换行)
1
2var text3 = """我是一个字符串
我还可以换行""";
2.6.2 转义字符
如果字符串中包含单引号,可以使用双引号定义法:
1 | String str = "Hello 'Dart'"; |
如果字符串中包含双引号,可以使用单引号定义法:
1 | String str = 'Hello "Dart"'; |
还有一个通用的方法,就是使用转义符 \
,在引号前面加上 \
表示后面的字符是普通字符串:
1 | String str = "Hello \"Dart\""; |
同样,如果你想在字符串中输出 \t
,可以这样写( \t
是制表符,同样 \n
是换行符,如果想在字符串中输出 \t
或 \n
等特殊字符,也是需要对斜杠 \
进行转义):
1 | String str = "Hello \\t \"Dart\""; |
2.6.3 字符串拼接
-
方式一:使用插值表达式
在 Dart 中,可以使用
字符串插值(${} )
的方式进行字符串格式化和拼接。1
2
3
4
5
6
7
8void main() {
String name = 'doubi';
int age = 18;
// 使用${}进行字符串插值
String message = "我的名字是${name},,今年${age}岁,明年就要${age+1}岁了";
print(message); // 输出:我的名字是doubi,,今年18岁
}可以看到在
${}
括号内填写的是变量和执行任意的 Dart 表达式。如果直接拼接变量,还可以直接使用$
:1
2
3
4
5
6
7void main() {
String name = 'doubi';
int age = 18;
String message = '我的名字是$name,今年$age岁,明年就要${age+1}岁了';
print(message);
} -
方式二:使用加号拼接
如果是字符串或字符串变量之间的拼接,直接使用
加号+
进行拼接即可,例如:1
2
3
4
5void main() {
String name = "张三";
String meaasge = name + "是法外狂徒";
print(meaasge);
}如果是拼接其他类型,需要先转换为字符串,然后再拼接,有点麻烦:
1
2
3
4
5
6
7
8void main() {
String name = "张三";
int age = 18;
String meaasge = "年龄为"+ age.toString() + "的" + name + "是法外狂徒" + ",明年他的年龄就是" + (age+1).toString() + "岁了";
print(meaasge); // 输出:年龄为18的张三是法外狂徒,明年他的年龄就是19岁了
}需要调用
.toString()
方法将数字、bool、对象等类型转换为字符串,然后再拼接。
2.6.4 判断字符串非空
可以使用 .isEmpty
和 .isNotEmpty
来判断字符串是否为空字符串(空字符串就是没有内容的字符串)。
1 | void main() { |
2.6.5 浮点数格式化
在输出浮点数的时候,我们可以指定输出的浮点数的精度。
1 | void main() { |
使用 toStringAsFixed()
方法将浮点数格式化为固定位数的小数,结果会四舍五入。
2.7 运算符
Dart 中常见的运算符有:算数运算符、赋值运算符、关系运算符。
2.7.1 算数运算符
Dart 中常见的算数运算符如下:
运算符 | 描述 | 示例 |
---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取余 | a % b |
~/ | 整除 | a ~/ b |
1 | void main() { |
2.7.2 赋值运算符
赋值运算符用来给变量赋值。
运算符 | 描述 | 举例 |
---|---|---|
= | 赋值运算符 | 把 = 右边的值赋值给左边的变量 |
1 | void main() { |
除了赋值运算符,下面还有复合赋值运算符。复合赋值运算符就是经过计算后,将值赋给前面的变量。赋值运算符使得代码更加简练,效率更高。
运算符 | 描述 | 举例 |
---|---|---|
+= | 加法 赋值运算符 | c += a 等效于 c = c + a |
-= | 减法 赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法 赋值运算符 | c = a 等效于 c = c a |
/= | 除法 赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模 赋值运算符 | c %= a 等效于 c = c % a |
~/= | 整除 赋值运算符 | c ~/= a 等效于 c = c ~/ a |
1 | void main() { |
2.7.3 自增自减运算符
Dart 中的自增自减运算符包括 ++
和 --
。它们可以用于对变量进行加 1 或减 1 操作。
1 | void main() { |
注意:自增自减运算符可以放在变量的前面或后面,这会影响到表达式的值。如果运算符放在变量的前面,表示先加减,后使用;如果运算符放在变量的后面,表示先使用,后加减。
1 | void main() { |
--
操作符也是一样的。
2.7.4 关系运算符
关系运算符也就是比较运算符,主要有以下几种:
运算符 | > | < | > = | <= | == | != |
---|---|---|---|---|---|---|
含义 | 大于 | 小于 | 大于等于 | 小于等于 | 等于 | 不等于 |
1 | void main() { |
关系运算符得到的结果是 bool 类型,在后面可以通过使用关系运算符来进行条件的判断。例如身高大于 120cm 就要买儿童票等场景。
2.7.5 逻辑运算符
主要有以下三种:
运算符 | && | || | ! |
---|---|---|---|
含义 | 与,两边条件同时满足 | 或,两边条件满足一个即可 | 非,取反值,真为假,假为真 |
1 | void main() { |
逻辑运算符可以用来判断多个 bool 类型的条件:
1 | void main() { |
!(a > 5)
是将 a > 5
的结果取反。 a > 5
结果为 false,取反则为 true。
2.7.6 逻辑运算符的注意事项
-
逻辑运算符的优先级:
!
>&&
>||
1
2
3
4void main() {
bool result = !(1 < 2) && 3 == 3 || 1 == 3 && 2 <= 3;
print(result); // 打印:false
}可以将逻辑运算的结果赋值给一个变量的。当一个逻辑运算语句中同时包含与、或 、 非运算的时候,会按照优先级进行运算。所以上面先运算
!(1 < 2)
,然后运算!(1 < 2) && 3 == 3
,然后运算1 == 3 && 2 <= 3
,最后运算||
两边的结果。 -
逻辑短路
逻辑短路就是在进行逻辑运算的时候,如果已经能够得到最后的值,就不会再继续进行判断了。只有与运算符
&&
和或运算符||
存在逻辑短路。1
2
3
4
5void main() {
int num = 10;
bool b = num > 20 && num < 40;
print(b);
}在执行上面代码的时候,
num > 20
已经不成立了,而&&
运算需要两边都满足,所以后面的条件成不成立都不会影响最终逻辑表达式的结果,所以&&
后面的num < 40
就不会再继续判断了,这就是逻辑短路。同样
||
运算符:1
2
3
4
5void main() {
int num = 10;
bool b = num < 20 || num > 40;
print(b);
}在执行上面代码的时候,
num < 20
已经成立了,||
运算只要一边满足即可,所以整个逻辑表达式肯定是成立的,所以||
后面的num > 40
就不会继续判断了。