Dart语言(二)内置的数据类型
Dart内置支持下面这些类型:
- numbers 数字
- strings 字符串
- booleans 布尔
- lists(也被称之为arrays)list和数组
- sets set集合
- maps map集合
- runes(用于在字符串中表示Unicode字符串)
- symbols 符号
我们可以直接使用字母量来初始化上面的这些类型。例如 'this is a string'是个字面上的字符串,true是一个字面上的布尔。
由于Dart中每个变量引用的都是一个对象,一个类的实例,通常使用构造函数来初始化变量。一些内置的类型具有自己的构造函数。例如,Map()构造函数类创建map,就 new Map();
Numbers(数值)
Dart支持两种类型的数字:
int:整数值,其取值通常位于-2的53次幂和2的53次幂。
double:64-bit(双精度)浮点数。
int和double都是num的子类。num类型定义了基本的操作符,例如+、-、* 、/ ,还定义了abs()、ceil()、和floor()等函数。位操作符,例如 >> 定义在int类中。如果num或者其子类型不满足你的要求,可以参考dart:math库。
注意:不在-2的53次幂到2的53次幂范围内的整数在Dart中的行为和JavaScript中表现不一样。原因在于Dart具有任意精度的整数,而JavaScript没有。
整数是不带小数点的数字。下面是一些定义整数的方式:
var x = 1;
var hex = 0xDEADBEEF;
var bigInt = 34653465834652437659238476592374958739845729;
如果一个数带小数点,则其为double,下面是定义double的一些方式:
var y = 1.1;
var exponents = 1.43e5;
字符串和数字之间转换的方式:
//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 onAsString = 1.toString();
assert(oneAsString = '1');
//double -> String
String pigAsString = 3.14159.toStringAsFixed(2);
assert(pigAsString = '3.14');
整数类型支持传统的位移操作:<<、>>、&和 |。例如:
assert((3 << 1) == 6); //0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111
数字为编译时常量。很多算术表达式只要器操作数是常量,则表达式结果也是编译时常量。
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;
Strings字符串
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.";
可以在字符串中使用表达式,用法是这样的: ${expression} 。如果表达式是一个标识符,可以省略{}。如果表达式的结果是为一个对象,则Dart会调用对象的toString()函数来返回一个字符串。
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' ==
'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');
注意: == 操作符判断两个对象的内容是否一样。如果两个字符串包含一样的字符编码序列,则他们是相等的。
可以使用 +
操作符来把多个字符串链接为一个,也可以把多个 字符串放到一起来实现同样的功能:
var s1 = 'String ' 'concatenation'
" works even over line breaks.";
assert(s1 == 'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator '
+ 'works, as well.';
assert(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.""";
通过一个r前缀可以创建一个"原始raw"字符串:
//参考 Runes 来了解如何在字符串 中表达 Unicode 字符。
var s = r"In a raw string, even \n isn't special.";
字符串是编译时常量, 带有字符串插值的字符串定义,若干插值表达式引用的为编译时常量则其结果也是编译时常量。
// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = const [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
booleans布尔值
为了代表布尔值,Dart 有一个名字为 bool 的类型。 只有两个对象是布尔类型的:true
和 false
所创建的对象, 这两个对象也都是编译时常量。
当 Dart 需要一个布尔值的时候,只有 true
对象才被认为是 true。 所有其他的值都是 flase。这点和 JavaScript 不一样, 像 1
、 "aString"
、 以及 someObject
等值都被认为是 false。
例如,下面的代码在 JavaScript 和 Dart 中都是合法的代码:
var name = 'Bob';
if (name) {
// Prints in JavaScript, not in Dart.
print('You have a name!');
}
如果在 JavaScript 中运行,则会打印出 “You have a name!”,在 JavaScript 中 name
是非 null 对象所以认为是 true。但是在 Dart 的生产模式下 运行,这不会打印任何内容,原因是 name
被转换为 false了,原因在于 name != true
。 如果在 Dart 检查模式运行,上面的 代码将会抛出一个异常,表示 name
变量不是一个布尔值。
下面是另外一个在 JavaScript 和 Dart 中表现不一致的示例:
if (1) {
print('JS prints this line.');
} else {
print('Dart in production mode prints this line.');
// However, in checked mode, if (1) throws an
// exception because 1 is not boolean.
}
注意:上面两个示例只能在Dart上产模式下运行,在检查模式下,会抛出异常 变量不是所期望的布尔类型。
Dart 这样设计布尔值,是为了避免奇怪的行为。很多 JavaScript 代码 都遇到这种问题。 对于你来说,在写代码的时候你不用这些写代码: if (nonbooleanValue)
,你应该显式的 判断变量是否为布尔值类型。例如:
// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN)
Lists集合
也许 array (或者有序集合)是所有编程语言中最常见的集合类型。 在 Dart 中数组就是 List 对象。所以 通常我们都称之为 lists。
Dart list 字面上和 JavaScript 的数组字面上类似。下面是一个 Dart list 的示例:
var list = [1, 2, 3];
Lists 的下标索引从 0 开始,第一个元素的索引是 0,list.length - 1 是最后一个元素的索引。 访问 list 的长度和元素与 JavaScript 中的用法一样:
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; // Uncommenting this causes an error.
List类型有许多方便的操作list的方法,可以参阅Generics和 Collections。
Sets
在Dart中set是个无序的collection。
Version note: Although the Set type has always been a core part of Dart, set literals were introduced in Dart 2.2.
创建set集合示例:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Note: Dart infers that
halogens
has the typeSet<String>
. If you try to add the wrong type of value to the set, the analyzer or runtime raises an error. For more information, read about type inference.也就是说 你设定了泛型后,你就只能存放泛型指定的类型数据了,存放其他类型的会报错。
创建一个空的set集合,并指定泛型:
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
var names = {} 这种情况为什么是创建了一个map,而不是set集合呢,是因为Dart在进行语法检查时,如果没有指定类型,那么dart就会动态创建类型,由于dart语法中,map类型会优先于set集合出现,所以就会先创建一个Map<dynamic,dynamic>类型对象。
添加元素到set集合中使用add()或者addAll()方法:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
set集合的长度用.length:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
创建编译时的set集合,只需在集合前面加上const:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.
更多关于set集合的用法可以查看这里Generics and Sets.
Maps集合
通常情况下,一个map中存放的都是键值对,key和value都可以是任意类型的对象,但是key只能出现一次,value可以重复出现。
创建map示例:
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
Note: Dart infers that
gifts
has the typeMap<String, String>
andnobleGases
has the typeMap<int, String>
. If you try to add the wrong type of value to either map, the analyzer or runtime raises an error. For more information, read about type inference.要注意泛型
使用 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';
Note: You might expect to see
new Map()
instead of justMap()
. As of Dart 2, thenew
keyword is optional. For details, see Using constructors.在dart2中 new 是可选的,var gifts = new Map() 也可var gifts = map();
添加新的键值对和JavaScript中是一样的:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
获取map中的值跟JavaScript是一样的:
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
map中操作的key不存在就会返回null:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
用.length获取map中存放的key-value的数量:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
创建编译时map:
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // Uncommenting this causes an error.
For more information about maps, see Generics and Maps.
Runes
在 Dart 中,runes 代表字符串的 UTF-32 code points。
Unicode 为每一个字符、标点符号、表情符号等都定义了 一个唯一的数值。 由于 Dart 字符串是 UTF-16 code units 字符序列, 所以在字符串中表达 32-bit Unicode 值就需要 新的语法了。
通常使用 \uXXXX
的方式来表示 Unicode code point, 这里的 XXXX 是4个 16 进制的数。 例如,心形符号 (♥) 是 \u2665
。 对于非 4 个数值的情况, 把编码值放到大括号中即可。 例如,笑脸 emoji (😆) 是 \u{1f600}
。
String 类 有一些属性可以提取 rune 信息。 codeUnitAt
和 codeUnit
属性返回 16-bit code units。 使用 runes
属性来获取字符串的 runes 信息。
下面是示例演示了 runes、 16-bit code units、和 32-bit code points 之间的关系:
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));
}
运行结果如上。
注意: 使用 list 操作 runes 的时候请小心。 根据所操作的语种、字符集等, 这种操作方式可能导致你的字符串出问题。 更多信息参考 Stack Overflow 上的一个问题: 我如何在 Dart 中反转一个字符串?
Symbols符号
一个 Symbol object 代表 Dart 程序中声明的操作符或者标识符。 你也许从来不会用到 Symbol,但是该功能对于通过名字来引用标识符的情况 是非常有价值的,特别是混淆后的代码, 标识符的名字被混淆了,但是 Symbol 的名字不会改变。
使用 Symbol 来获取标识符的 symbol 对象,也就是在标识符 前面添加一个 #
符号:
#radix
#bar
Symbol 定义是编译时常量。