Dart内置类型

289 阅读6分钟

类型种类

  • numbers  数字
  • strings  字符
  • booleans  布尔
  • lists (also known as arrays)  列表或者叫数组
  • sets  无重复成员集合
  • maps  键值对集合
  • runes UTF-32定义的Unicode字符串
  • symbols 不透明的动态字符串名称

你可以通过字面量定义对应的变量类型,比如'a string'就定义了一个字符串类型,true就定义了一个布尔类型。
我们前面说过所有的变量都指向一个object也就是一个类的实例,所以你完全可以通过构造函数(部分内置类型有构造函数)来初始化变量,例如Map()就创建了一个map。

Numbers

Dart中Numbers类型包含两种子类,一个是int,一个是double

int

整型,最大不超过64位,根据平台的不同,支持的大小范围有所区别,在Dart vm中支持 -2 to 2 - 1,转换成js时,返回变成js中的数值范围,也就是 -2 to 2 - 1。

double

64位(双精度)浮点数,由IEEE 754标准规定。

定义

num类型包括基本运算符,如+, - ,/和*,也可以在其他方法中找到abs(),ceil()和floor()。(按位运算符,如>>)如果num及其子类型没有您要查找的方法,可以在 dart:math库中查找看看。
字面量定义方式

// 不包含小数点,int型
var x = 1;
var hex = 0xDEADBEEF;
// 包含小数点,double型
var y = 1.1;
var exponents = 1.42e5;
// dart2.1之后可以转化
double z = 1; // 等价于 double z = 1.0.

字符串转数字,和数字转字符串:

// 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');

整型定义了常见的未操作符,包括>>, &(and), |(or):

assert((3 << 1) == 6); // 0011 << 1 == 0110      0011向左移动一位。
assert((3 >> 1) == 1); // 0011 >> 1 == 0001      0011向右移动一位。
assert((3 | 4) == 7); // 0011 | 0100 == 0111     0011和0100取并集得0111

字面量定义的数字是编译时常量,所以他们运算后得出的结果也是编译时常量:

const a = 1;
const b = 2;
const plus = a + b;

String

Dart字符串是UTF-16代码组成,可以通过单引号表示,也可以用双引号:

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.'; // 通过\转义单引号
var s4 = "It's even easier to use the other delimiter."; // 双引号中单引号不需要转义,反之亦然。

字符串中使用变量通过关键字$,如果要使用表达式,那么使用${}:

var s = 'abc';
assert('im $s' == 'im abc');
assert('That deserves all caps. ' +
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. ' +
        'STRING INTERPOLATION is very handy!');

前面已经说过dart中都是object,所以比较两个字符串是否相等,其实是它们是否具有相同的字符序列。
在字符串前面加上r,表示行字符串,也就是不转义特殊字符。比如**\n、\r**
字符串拼接可以通过相邻字符或者通过 + 拼接, 这样也可以解决字符串过长的问题:

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
var s2 = 'The + operator ' + 'works, as well.';

另一种字符串换行的方式:

var s1 = '''
You can create
multi-line strings like this one.
'''
var s2 = """This is also a
multi-line string.""";

字面量定义的字符串是编译时常量,而且只要插入字符串的表达式是编译时常量(null,string, number,boolean),那么拼接出来的表达式也就是常量:

// 这些可以拼接出字符创常量
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// 这些不可以
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

Boolean

Boolean只有两个值truefalse,它们都是编译时常量。
由于dart的类型安全,想if这样的语句中,条件只能是boolean值:

// isEmpthy 返回的是boolean
var fullName = '';
assert(fullName.isEmpty);

// 是否小于等于0
var hitPoints = 0;
assert(hitPoints <= 0);

// 是否等于null
var unicorn;
assert(unicorn == null);

// 是否是非数字
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

List

也就是其他语言中常用的array,字面量定义方式和js一样:

var list = [1, 2, 3];

dart中的类型推断会把上面的list,推断为list,插入非int值,会导致错误。详情:type inference
索引从0开始,length属性返回list长度,和js一样:

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

可以在list前面加上const创建一个编译时常量list:

var constantList = const [1, 2, 3];
// constantList[1] = 1; // 取消注释会报错,应为这个list无法被修改。

Dart2.3提供了......?方便合并多个list:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
// 对于初始化但是没有赋值的变量,可以使用...?,这个变量将被忽略
var lis3;
var list4 = [0, ...?list3];
assert(list4.length == 1);

Dart2.3还提供了list中的iffor,代码如下:

// 只有promoActive为true,Outlet才会被添加进list
var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];
// 通过for关键字,直接把循环结果插入list
var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

Set

无序且所有项不重复的集合。字面量定义方法:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

dart中的类型推断会把上面的halogens,推断为set,插入非string值,会导致错误。详情:type inference
创建空的set:

// 指定set的子项类型
var names = <String>{};
// 指定变量为set类型
Set<String> ages = {}; // This works, too.
// 由于map和set的符号一样,且map更先引入dart,所以直接定义{},其实定义的是map
// var names = {}; // Creates a map, not a set.

添加成员和返回长度:

var elements = <String>{};
// 添加一个项
elements.add('fluorine');
// 添加一整个set,halogens在上面的代码中已定义。
elements.addAll(halogens);
// length属性返回长度,由于fluorine重复了所以长度为5
assert(elements.length == 5);

创建编译时常量:

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // 由于constantSet指向一个编译时常量,所以无法添加新的成员进入,当然我们完全可以修改变量指向一个新的object。

Maps

键值对(key-value)的集合,keyvalue可以是任何Dart中的类型,其中key不允许重复,value没有限制,完全可以多个key有相同的value
定义Map:

// 字面量定义
var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
// 构造函数定义
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';

dart中的类型推断会把上面的gifts,推断为Map<String, String>,插入错误类型值,会导致错误。详情:type inference
常用属性和方法:

// 通过[]来取值,没有的键将会返回null
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
// length返回map的长度
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

创建编译时常量:

final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
// constantMap[2] = 'Helium'; // 由于constantMap指向一个编译时常量,所以无法修改它的值,当然我们完全可以修改变量指向一个新的object。

dart2.3之后,Map也支持......?用法和list中相似:

var defaultParams = { "age": 12 };
var params = {
  "userId": 123,
  "timeout": 300,
  ...defaultParams
};
// ...?
var defaultParams;
var params = {
  "userId": 123,
  "timeout": 300,
  ...?defaultParams
};

Runes

Rune是UTF-32编码的字符串。它可以通过字符串转换成特定的文字,比如表情符号。
Dart中String类型是UTF-16编码的,所以String中药表示Rune需要特殊的声明方式:\uXXXX,比如♥是\u2665,如果数字位数大于或小于4位需要用大括号包起来,比如:😆是 \u{1f600}
String提供了codeUnits和codeUnitAt等属性来获取runes16-bit字符单元信息:

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}
// 打印结果
👏
[55357, 56399]
[128079]
♥  😅  😎  👻  🖖  👍

runes和普通字符串混合使用时,如果此时反转字符串需要特别注意:

var input = "Music \u{1d11e} for the win"; 
print(input); // Music 𝄞 for the win
// 这里出现了乱码,是因为我们把runes当做了普通的字符串直接反转,导致反转后无法识别。
print(input.split('').reversed.join()); // niw eht rof �� cisuM
// 我们可以吧整个字符串转成runes然后在反转,再转换成普通字符串
print(new String.fromCharCodes(input.runes.toList().reversed)); // niw eht rof 𝄞 cisuM

Symbols

Symbol对象表示Dart程序中声明的运算符或标识符。Symbol是存储人类可读字符串与方便计算机优化使用的字符串之间关系的一种方法。开发中很少使用,但是它们对于通过名称引用标识符的API非常有用。
Symbols是编译时常量,具体用法请看API