简介:
Dart是谷歌开发的跨平台的计算机高级语言。Dart是面向对象的、类定义的、单继承的语言。它的语法类似C语言(更加类似于swift或者kotlin),可以转译为JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、泛型(reified generics)、可选类型(optional typing)和静态推断类型sound type system。
Hello world! :
main()函数是Dart的入口函数,也是所有Dart语言的开端:
void main() {
print('Hello, World!');
}
Dart中重要的概念:
1.Dart中一切皆对象:
在其它面向对象语言中变量类型一般包含基础数据类型和对象类型(或者引用类型),例如swift或者java。在Dart中,声明的每个变量都是一个类的对象;无论是数字(numbers
),函数(functions
)和null
都是对象;并且除了null
(如果你启用了sound null safety
),所有对象继承自Object
类。
2.Dart中是强引用类型的(strong
):
不像swift或者OC中有weak
弱引用,Dart中的变量或者属性都是strong
强引用的。虽然Dart是强类型的,但类型注释是可选的,因为Dart可以推断类型。在下面的代码中,number被推断为int类型:
var number = 23;
print(number.runtimeType); // 打印int
3.Dart中是空安全的(null safety
):
null safety
是在Dart 2.12中引入的。当您选择null safety
时,您代码中的类型默认情况下是不可为空的,这意味着值不能为空,除非您说它们可以为空。示例代码如下:
int? number2; // number2可以为空也可以是int类型的值
number2 = null;
number2 = 34;
int number3;
number3 = null; // 报错:number3不能为null
4.Dart中可以推断确定变量类型:
Dart中推断确定变量的类型有两种,一种是在编译时,一种是在运行时。在Dart中,声明变量和属性基本都是编译时已经确定其类型,但是用关键字dynamic
修饰的变量和属性是在编译时才能确定的。
dynamic
修饰的变量和属性的值进行任何成员访问,但可能会失败,并在运行时抛出异常。如果您确实想要那种有风险但灵活的动态分派,那么使用dynamic
是合适的类型。
否则,更喜欢使用Object?
或Object
。在访问值之前,依赖于is检查和类型提升,以确保值的运行时类型支持希望访问的成员。
Object? number; // 可以为任意类型的值
dynamic number2; // 可以为任意类型的值
number = null;
number = 12;
number.toString();
number = '123'; // 上一行number是int值,可以改变变量的类型
// print(number + 1); // 编译时报错,number2是String值
if (number is int) { // 判断类型
print(number + 1);
}
print(number.runtimeType);
number2 = null;
number2 = 12;
number2 = '123';
if (number2 is int) { // 判断类型
print(number2 + 1); // 编译时报错
}
print(number2 + 1); // 编译时不报错,运行时报错,number2是String值
5.Dart支持泛型类型:
Dart支持泛型类型,如List<int>(整数列表)或List<Object>(任何类型的对象列表)。
6.Dart支持顶级函数和变量
Dart支持顶级函数(如main())和变量,以及绑定到类或对象的函数或者变量(分别为静态方法或者静态变量和实例方法或者实例变量)。还可以在函数中创建函数(嵌套函数或局部函数)。实例变量有时被称为字段或属性。
7.Dart没有权限修饰符:
与Java不同,Dart没有public
、protected
和private
权限修饰符。如果标识符以下划线(_)开头,则它是其库或者类的私有。
8.私有变量、常量、函数都以下划线开头:
标识符可以以字母或下划线(_)开头,然后是这些字符和数字的任意组合。
class Some {
// 静态变量,类属性
static int type = 0;
// 实例变量,实例属性,实例字段
late final String name;
// 私有属性
late String _privateProperty;
// 可供外界访问方法
void show() {
_show();
}
// 静态方法,类方法
static void showType() {
print(type);
}
// 私有函数
void _show() {
print(_privateProperty);
}
}
9.Dart中的表达式和语句:
Dart语法中有expressions
( 表达式有运行时值)和 statements
(语句没有运行时值 )。 例如,条件表达式condition ? expr1 : expr2 的值可能是 expr1 或 expr2 。 将其与 if-else 语句相比较,if-else 语句没有值。 一条语句通常包含一个或多个表达式,相反表达式不能直接包含语句。
var number = 1;
final bool isBigger;
if (number > 10) {
isBigger = true;
}
else {
isBigger = false;
}
var isBigger2 = (number > 10) ? true : false;
10.Dart中警告和错误
Dart工具可以报告两种问题:warnings
(警告)和errors
(错误)。警告只是表示您的代码可能无法工作,但它们不会阻止您的程序执行。错误可以是编译时的,也可以是运行时的。编译时错误会阻止代码执行;运行时错误会导致在执行代码时引发异常。
Dart中的关键字
关键字 | 关键字 | 关键字 | 关键字 |
---|---|---|---|
abstract 2 | else | import 2 | show 1 |
as 2 | enum | in | static 2 |
assert | export 2 | interface 2 | super |
async 1 | extends | is | switch |
await 3 | extension 2 | late 2 | sync 1 |
break | external 2 | library 2 | this |
case | factory 2 | mixin 2 | throw |
catch | false | new | true |
class | final | null | try |
const | finally | on 1 | typedef 2 |
continue | for | operator 2 | var |
covariant 2 | Function 2 | part 2 | void |
default | get 2 | required 2 | while |
deferred 2 | hide 1 | rethrow | with |
do | if | return | yield 3 |
dynamic 2 | implements 2 | set 2 |
避免使用这些词作为标识。但是,如果有必要,标记有上标的关键字可以是标识符。
标识符命名规则:
- 变量的名称必须有数字,字母,下划线和美元符($)组成
- 标识符不能以数字开头
- 标识符不能是保留字或关键字,见关键字说明
- 标识符是区分大小写的;例如:
name
和Name
不是同一个变量 - 标识符(变量和函数)一定要通俗名义
变量:
1.变量的定义:
变量定义有三种常见的方法,一种是var
定义,一种是指定具体类型的定义,还有一种是dynamic
定义。
在空安全模式下(null safety
),变量在使用之前必须被初始化赋值,除非该变量允许为空(例如int?
)。
1.1var
定义变量:
var
定义变量,不明确变量的类型,Dart自己会有类型检查,会根据var
关键字在定义变量时所赋予的初值的类型明确变量的类型。var
定义变量根据赋值的时机分为两种情况:一种是定义时随即赋值;一种是先声明变量,在之后代码中另行赋值。
1.1.1var
定义变量随即赋值:
上述中说到,在赋值时确定了变量类型,在赋值之后,可以赋值其它类型吗?代码如下:
var number2 = 12; // 等价于 int number2 = 12;
number2 = 14;
var result = number2 + 1; // 正常运行
// number2 = null; // 编译报错
// number2 = '123'; // 编译报错
如代码所示,这种声明变量并赋值的变量,其后无法进行其它类型的赋值,它与指定具体类型定义变量等价。
1.1.2var
定义变量后,另行赋值:
与1.1.1中问题进行对比:
var number; // 等价于 Object? number;
number = 12;
number = null; // 不会报错
number = '123'; // 不会报错
// var result = number + 1; // 编译时通过,运行时报错,上一行代码表示,number为String类型
var result2 = number + '1'; // 正常运行
如代码所示,这种声明并赋值的变量,其后可以进行其它类型的赋值,并且该变量的类型与最近一次赋值的类型相同;但是之后对其进行已赋值过的类型进行操作,编译时不会报错,运行时会报类型不匹配的错误;该定义变量与指定类型为Object?
变量等价。
1.2指定具体类型的定义变量:
int number = 1;
String str = '123';
1.3动态变量即dynamic
定义的变量:
dynamic
定义的变量,编译时不会进行其类型的确定,而是在运行时确定;并且该变量可以进行任意类型的操作,编译时不报错,只有在运行时才会报错;其运行时的类型与最近一次赋值的类型相同。
dynamic number = 1;
var result = number + '1'; // 编译通过,运行时报类型不匹配错误
number = '123';
var result2 = number + '4'; // 正常运行
dynamic
一般用于泛型(以后会讲到),且必须对其类型有确切的掌握,不然运行时报错就不可避免了。
2.初始值(Default value
):
- 具有可空类型的未初始化变量的初始值为
null
, - 在空安全模式下(
null safety
),局部变量在使用之前必须被初始化赋值,除非该变量允许为空(例如int?
)。 - 顶级和类变量是延迟初始化的,且使用之前必须被初始化赋值。
int? number2;
print(number2);
int number;
// print(number); // 空安全模式下,number没有初始化,且不能为空,所以报错
number = 2;
print(number); // 正常运行
class Some {
// static int type; // 报错
static int type = 1;
}
常量:
定义:
不更改的变量或者初始化后无法更改的变量就是常量,在Dart中声明常量用关键字const
或者final
。
const
的final
联系:
- 都是编译时常量;
- 只能初始化赋值一次,其后无法修改值;
- 在类中都可以和
static
一起使用表示类级别的属性。
const
的final
区别:
-
const
常量声明时可以省略,而final
不能省略; - 类中声明属性和字段使用
final
,不用const
; -
const
常量为编译时常量,声明时必须初始化赋值,而final
常量还是运行时常量可以先声明再赋值(即常说的懒加载),但是final
常量必须在使用前进行初始化赋值; -
const
修饰对象时,对象的属性无法修改,而final
修饰对象,对象属性可以修改。
内置类型:
Dart支持的类型:
-
Numbers (数值类型
int
,double
) -
Strings (字符串
String
) -
Booleans (
bool
) -
Lists (
List
,常见的数组) -
Sets (集合
Set
) -
Maps (哈希表或者字典
Map
) -
Runes (
Runes
;通常被“characters
”API所取代) -
Symbols (符号
Symbol
) - 空值
null
(空类Null
)
Dart特殊的类型:
-
Object
:除Null
外的所有Dart类的超类; -
Future
和Stream
:用于异步支持; -
Iterable
:用于for-in循环和同步生成器函数; -
Never
:表示一个表达式永远不能成功完成求值,通常用于总是抛出异常的函数; -
dynamic
:表示要禁用静态检查,通常你应该使用Object?
代替; -
void
:表示该值从未被使用。通常用作返回类型。
Numbers类型:
整形数值类型(int
);其取值范围,不大于64位的整数值,取决于平台;在本地平台上,值可以从-263到263 - 1。在web上,整数值表示为JavaScript数字(64位浮点值,没有小数部分),取值范围从-253到253 - 1。
double
类型:64位(双精度)浮点数,由IEEE 754标准指定。
int
和double
都是 num
的子类。num类型包括基本操作符,如+、-、/和*,在这里您还可以找到abs()
、ceil()
和floor()
等方法。(位操作符,如>>,定义在int类中。)如果num及其子类型没有您要寻找的内容,那么dart:math
库可能有。
var x = 1;
var hex = 0xDEADBEEF;
var exponent = 8e5;
var y = 1.1;
var exponents = 1.42e5;
num n = 1; // x可以是int或者double
n += 2.5;
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 | 4) == 7); // 0011 | 0100 == 0111
assert((3 & 4) == 0); // 0011 & 0100 == 0000
Strings类型:
- String类型包含一个UTF-16代码单元序列;
- 可以用
''
或者""
初始化赋值; - 可以用
r
初始化赋值; - 可以用
‘’‘’‘’
或者""""""
初始化多行字符串; - 可以用
+
拼接字符串; - 可以用
==
判断字符串内容相同。
String s1 = '123';
String s2 = "123";
String s3 = r"123";
String s4 = '''123
456
789
''';
String s5 = """123
456
789
""";
var s6 = "I am " + "Lucy!";
print("object" == "object"); // true
Booleans类型:
-
bool
类型,两个值true
和false
;它们都是编译时常量; - 条件判断没有隐式类型转换。
var number = 123;
var str = '123';
if (number == str) {
print("隐式转换");
}
else {
print("没有转换"); // 没有转换
}
Lists类型:
-
List
中元素可以重复; - 支持
if
,for
,...
,...?
等语法;
List
数组类型,常见初始化和操作代码如下:
var intList = [1, 2, 3];
List<int> intList3 = <int>[];
var list2 = [0, ...intList];
var strList = ['Car', 'Boat','Plane',];
List<String> strList2 = <String>[];
var hasZheng = true;
var strList3 = [
'周',
'吴',
if (hasZheng) '郑',
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
print(listOfStrings);
Sets类型:
-
Set
中元素唯一; - 支持
if
,for
,...
,...?
等语法;
Set
集合类型,常见初始化和操作代码如下:
var intSets = {1, 1, 1};
var intSets2 = <int>{};
intSets2.add(2);
intSets2.addAll(intSets);
print(intSets); // {1}
print(intSets2); // {2, 1}
var hasZheng = true;
Set<String> strSets = {'周', '吴', if (hasZheng) '郑'};
Set<String> strSets2 = {...strSets, '王'};
print(strSets2); // {周, 吴, 郑, 王}
Maps类型:
-
Map
是一个关联键(key
)和值(value
)的对象的集合; - 键和值都可以是任何类型的对象;
- 每个键只出现一次,但您可以多次使用相同的值;
- 支持
if
,for
,...
,...?
等语法;
Set
集合类型,常见初始化和操作代码如下:
var nameMap = {"first" : "周", "second" : "吴"};
nameMap['third'] = "郑";
Map<int, String> someMap = {1 : "周", 2 : "吴"};
var someMap2 = {1 : "周", 2 : "吴", ...someMap};
print(nameMap); // {first: 周, second: 吴, third: 郑}
print(someMap2); // {1: 周, 2: 吴}