变量的类型指的是变量的特性或特征,比如表示数字类型、文本类型、集合类型等,表示的是一类数据。
Dart提供以下的内置类型:
- 数字:int, double (整型(表示整数),浮点型(表示小数))
- 布尔:bool (true/false)
- 字符串:String
- 列表:List (也被称为
arrays
数组) - 集合:Set
- 映射:Map
- Null:null
Dart 中最基础类型只有 bool
和 num
,表示真假
和数字
。其他类型为聚合类型。null属于特殊类型,表示空,它唯一一个不属于Object的类型。
此外,数据类型还有Runes与Symbols。
数字类型
整型与浮点型
int count = 49; // 整型
double pi = 3.14; // 浮点型
int
和 double
都是 num
的子类。因此也可以用num表示数字,但是变量的类型会在编译执行后,自动转换为特定的int类型或double类型。
runtimeType
属性可以查看一个变量的运行时类型。
查看num
运行时类型:
num a = 57; // 整型
num b = 3.28; // 浮点型
print("a:${a.runtimeType}");
print("b:${b.runtimeType}");
/* 输出 */
a:int
b:double
num
是一个抽象类。抽象类没有实现,不能实例化,任何抽象类,在运行时都是具体的实现类型。
数字的方法
num
常用的方法
num b = 3.28;
b.abs(); // 绝对值 : 3.28
b.ceil(); // 向上取整: 4
b.floor(); // 向下取整: 3
b.round(); // 四舍五入取整: 3
b.truncate(); // 去除小数部位取整: 3
String str = b.toString(); // 转换为字符串: 3.28
String v = b.toStringAsFixed(1); // 四舍五入,保留几位小数,返回字符串: 3.3
- 解析为数字
double
和int
的parse
方法用于解析数据获取数字;tryParse
方法用于解析获取数字,如果无法转换为对应数字,将会返回null。
double result1 = double.parse('3.3');
int result2 = int.parse('10');
double? result3 = double.tryParse('a3');
int? result4 = int.tryParse('10.2');
- 进制转换
int
类型提供了进制转换方法toRadixString
,可以把整型转化为指定的进制,以字符串形式输出。
如下将变量转换为2进制、16进制字符串:
int a = 2022;
print(a.toRadixString(2)); // 11111100110
print(a.toRadixString(16));// 7e6
parse
/tryParse
方法将其他进制的字符串转换为int类型。
int? int1 = int.tryParse('7e6',radix: 16);
print(int1); // 2022
int? int2 = int.tryParse('11111100110',radix: 2);
print(int2); // 2022
布尔bool
布尔类型表示真假。只有两个取值:
bool a=true;
bool b=false;
字符串
字符串类型是使用最广泛的类型,表示文本形式的数据,任何数据或信息都可以通过文本表示出来。
字符串表示若干个字符组成的对象。Dart字符串使用的是UTF-16编码的字符序列。
字符串定义
Dart中字符串支持单引号
、双引号
、三单引号
、三双引号
形式的字面量。
String a = 'hello, 单引号';
String b = "hello, 双引号";
String c = '''hello, 三单引号''';
String d = """hello, 三双引号""";
单引号和双引号没有任何区别,根据习惯使用即可(偏推荐单引号)。唯一的一个区别是对字符串内引号的转义。
String a = 'hello, \'单引号中转义单引号\'';
String b = "hello, '双引号中直接使用单引号'";
String c = 'hello, "单引号中直接使用双引号"';
String d = "hello, \"双引号中转义双引号\"";
三引号
可以表示多行字符串。
String e = '''
你好,我是‘
三个单引号
"组成的"多行
字符‘串
''';
r前缀表示原始字符串
字符串前加上 r 前缀创建原始(raw
)字符串(即不会被做任何处理(比如转义)的字符串)。
var s = r'在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。';
主要是保证输入的内容保持不变,原样输出。
模板字符串(字符串插值)
通常可以通过+
号实现字符串的拼接。
比如多个字符串变量:
String str1 = '我们';
String str2 = '工作';
String str3 = '更好的人';
int n=0;
String result = str1 + '努力' + str2 + ',成为' + str3 + '。只有我失败了...' + (n+2).toString();
print(result); // 我们努力工作,成为更好的人。只有我失败了...2
当变量很多时,+
号就非常不简洁、麻烦。
Dart提供了字符串插值的方式,在字符串中通过 ${变量}
插入变量,方便拼接。{}
中还可以进行简单的计算。如果 {}
中只有变量名称,可以省略 {}
。
比如下面,{n+3+3}
内执行运算时不可省略。
String result2 = '${str1}努力$str2,成为$str3。只有我失败了...${n+3+3}';
print(result2); // 我们努力工作,成为更好的人。只有我失败了...6
string interpolation
字符串插值。 这种字符串也会叫做模板字符串。组成字符串的形式叫字符串模板。
字符串方法
- 索引获取字符
字符串是一组字符组成的聚合对象,可以通过[]
访问第几个字符,字符位置也叫索引,索引下标从0开始。
比如str[5]
表示索引6的字符,顺序为第5个。
length
属性可以获取字符长度。
String str = '我是一个中文字符串';
print(str[5]); // 文
print(str[str.length-1]); // 串
substring
截取字符串
substring
方法用于截取字符串。需要传入两个参数:分别表示 起始索引
和 结束索引
,返回的子字符串包含起始字符,不包含结束字符。第二个参数结束索引
可省略,表示一直截取到字符结尾。
String str = '我是一个中文字符串';
print(str.substring(4)); // 中文字符串
print(str.substring(4,7)); // 中文字
trim
去除头尾空白符号;trimLeft
只去除开头的空白符;trimRight
只去除末尾的空白符:
String str = ' 我是一个中文字符串 ';
print(str.trim());
print(str.trimLeft());
print(str.trimRight());
toUpperCase
将字符全部转为大写字母;toLowerCase
将字符全部转为小写字母。startsWith
是否以指定字符串开头;endsWith
是否以指定字符串结尾;contains
是否包含指定字符串。返回bool类型(true/false)。indexOf
返回首次出现指定字符串的索引,不存在则返回-1
。replaceAll
替换字符串;split
将字符串拆分为列表List;padLeft
字符串左补齐指定宽度的指定字符,默认补充空格;padRight
字符串右补齐。
多数String相关的方法都支持正则表达式,因此可以实现更多、更灵活的字符串处理。
List列表
List
对象表示多个元素组成的序列,列表用 []
进行定义,其内通过 逗号,
来分隔元素。在其他语言中通常叫做组数(Array),是最常见的集合类型。
如下,使用 列表字面量(list literals
)创建一个繁体0~9的列表:
List<String> cnBigNumUnits = [
'零','壹','贰','叁','肆','伍','陆', '柒','捌','玖',
];
通过索引就可以访问某个元素。【索引从0开始】
print(cnBigNumUnits[3]);
一些常用属性:
- length 长度
reversed
翻转ListisEmpty
是否为空isNotEmpty
是否不为空
const
关键字创建一个编译时常量var constantList = const [1, 2, 3]; // constantList[1] = 1; // This line will cause an error.
扩展操作符(...)和 空感知扩展操作符(...?)
Dart 2.3 引入。
spread operator
扩展操作符 ...
和 null-aware spread operator
空感知扩展操作符 ...?
可以简介的将多个值插入到集合。
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
如果扩展操作符右边可能为null
,使用空感知扩展操作符(...?)可以避免产生异常
var list=null;
// ...
var list2 = [0, ...?list];
assert(list2.length == 1);
创建List时使用if或for
如下,使用collection if
创建List,可能包含3个或4个元素。
var nav = ['主页', '发现', '阅读', if (promoActive) '个人中心'];
使用collection for
操作列表中的元素之后添加到List中:
var ints = [1, 2, 3];
var strings = ['#0', for (var i in ints) '#$i'];
assert(strings[1] == '#1');
print(strings); // [#0, #1, #2, #3]
关于List泛型列表的具体类型【不推荐使用List】
可以看到上面定义cnBigNumUnits
时,类表类型为List<String>
,它是List的泛型表示,也就是实际类型是List<String>
。
<>
内是一个类型参数,通常传递类型,表示该List是泛型的一个具体类型的List。
使用类型推断,以及runtimeType
属性查看创建数组的具体类型:
var myList=[1,'2',3,'四'];
print(cn); // [1, 2, 3, 四]
print(cn.runtimeType); // JSArray<Object>
List myList2=[1,'2',3,'四'];
print(myList2);
print(myList2.runtimeType); // JSArray<dynamic>
print('---------------');
List myList3=[1,2,3];
print(myList3);
print(myList3.runtimeType); // JSArray<dynamic>
print('---------------');
var myList4=[1,2,3];
print(myList4);
print(myList4.runtimeType); // JSArray<int>
print('---------------');
var myList5=['一','二','三'];
print(myList5);
print(myList5.runtimeType); // JSArray<String>
可以看到,直接使用List
的类型为JSArray<dynamic>
,动态类型总是不推荐的。因此实际中,最好使用具体的泛型,如List<String>
、List<int>
等,使用类型推断var
,后面的列表也要尽量类型一致。
类表常见方法
修改元素值
[idx]
通过索引访问元素,使用=
赋值就可以修改元素
cnBigNumUnits[6] = '六';
print(cnBigNumUnits);
cnBigNumUnits[6] = '陆';
print(cnBigNumUnits);
添加元素
add
和addAll
方法用于在列表末尾添加元素;insert
和insertAll
方法在指定索引处添加元素。
addAll
、insertAll
的作用更像是拼接数组。
List<String> cnBigNumUnits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
cnBigNumUnits.add('拾');
cnBigNumUnits.add('佰');
cnBigNumUnits.addAll(['仟', '萬', '亿']);
cnBigNumUnits.insert(2, '点');
cnBigNumUnits.insertAll(2, ['横', '撇']);
print(cnBigNumUnits);
删除元素
removeAt(idx)
:删除 指定索引 的元素remove(item)
:删除 某个元素值removeLast()
:移除并返回最后一个元素removeRange(int start, int end)
:移除范围内的元素
cnBigNumUnits.removeAt(2);
cnBigNumUnits.removeAt(2);
cnBigNumUnits.remove('点');
print(cnBigNumUnits);
join()
List转换成字符串
List<String> cnBigNumUnits = [
'零','壹','贰','叁','肆','伍','陆', '柒','捌','玖',
];
print(cnBigNumUnits.join()); // 零壹贰叁肆伍陆柒捌玖
print(cnBigNumUnits.join(',')); // 零,壹,贰,叁,肆,伍,陆,柒,捌,玖
Set 集合
集合的使用和增删
通过大括号{}
定义一个集合,集合中元素用,
分割。
Set和数学中集合的概念一样,可容纳若干个元素,无序且不包含相同元素。Set中没有索引的概念。
Set<String> cnBigNumUnits = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
Set<String> cnBigNumUnits = {}
或var cnBigNumUnits = <String>{}
都可以创建空的集合。
add
添加元素到集合中,重复重复将不被添加进去。
remove
移除指定的元素。
addAll
和 removeAll
用来添加和移除多个元素。
cnBigNumUnits.addAll({'零', '元','角','分'});
cnBigNumUnits.addAll(['拾', '佰', '仟', '萬', '亿']);
cnBigNumUnits.removeAll({'元','角','分'});
集合运算
集合间的运算关系主要有交集(intersection)、并集(union) 、补集 (difference)。
Set<String> cnBigNumUnits = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
Set<String> part = {'零', '壹', '贰', '元', '角', '分'};
cnBigNumUnits.intersection(part); // 交集
// {零, 壹, 贰}
cnBigNumUnits.union(part); // 并集
// {零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖, 元, 角, 分}
cnBigNumUnits.difference(part); // 补集
// {叁, 肆, 伍, 陆, 柒, 捌, 玖}
Map 映射
Map
是用来关联key和value的对象,其中的键和值可以是任何类型的对象。每个 键 只能出现一次但是 值 可以重复出现多次。
在其他编程语言中,Map
映射也被称为字典类型(Dictionary
),或哈希类型(hash
)。
映射通过 {}
进行定义,其中包含若干个 key : vlaue
的键值对。下面使用 Map 字面量创建映射:
Map<String,String> dict = {
'about': '关于',
'boot': '启动',
'card': '卡片',
};
还可以使用Map构造器创建Map:
var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map<int, String>();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
Map通过[key]
来访问值
,如果key不存在,将会返回null;通过赋值=
可以修改某个key的value,如果key不存在则会添加。
remove(key)
用于移除元素。
// 访问
print(dict['card']); // 卡片
// 修改
dict['boot'] = '启动,靴子';
// 增加
dict['dog'] = '狗';
dict['cat'] = '猫';
//通过 key 删除元素
dict.remove('cat');
.length
返回Map键值对的数量。
Map 可以像 List 一样支持使用扩展操作符(... 和 ...?),以及集合的 if 和 for 操作。
List、Set、Map之间的关系和相互转换
- List 和 Set 可以相互转化
Set
中的元素是不重复的,如果 List
中有重复的元素,通过 toSet
方法转化为 Set
可以去除重复元素,再把 Set
通过 toList
转化为 List
,可以实现 去重 的需求。
List<String> cnNumUnits = ['零', '壹', '贰', '叁','贰', '贰'];
Set<String> cnNumSet = cnNumUnits.toSet();
print(cnNumSet); // {零, 壹, 贰, 叁}
List<String> cnNumUnique = cnNumSet.toList();
print(cnNumUnique); // [零, 壹, 贰, 叁]
List
通过asMap
方法可以返回一个Map
对象。其中键是索引,值是元素值
List<String> cnNumUnits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
Map<int,String> cnNumMap = cnNumUnits.asMap();
print(cnNumMap);
// {0: 零, 1: 壹, 2: 贰, 3: 叁, 4: 肆, 5: 伍, 6: 陆, 7: 柒, 8: 捌, 9: 玖}
- 通过
Map.fromIterables
方法,可以根据两个可迭代对象创建映射对象,前者是key
,后者是value
。(List
和Set
都是可迭代对象)
List<String> cnNumUnits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖','拾','佰','仟','萬'];
Set<int> numUnitsSet = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,100,1000,10000};
Map<int,String> map = Map.fromIterables(numUnitsSet,cnNumUnits);
print(map);
// {0: 零, 1: 壹, 2: 贰, 3: 叁, 4: 肆, 5: 伍, 6: 陆, 7: 柒, 8: 捌, 9: 玖, 10: 拾, 100: 佰, 1000: 仟, 10000: 萬}
Map
对象可以通过keys
和values
获取可迭代对象,再通过toList
和toSet
获得List
和Set
对象。
Map<String,String> dict = {'about': '关于', 'boot': '启动', 'card': '卡片'};
dict.keys.toList();
dict.values.toList();
dict.keys.toSet();
dict.values.toSet();
可空数据类型?
Dart中,通过在类型后面添加?
符号,表示该类型可为空。一个不可为空类型是不能赋值为null(通常也不需要设置为null),如果有必要使用null值,则必须通过?将类型变为可空类型。
可空类型:
int? a=null;
String? s=null;