Learning Dart - 类型
基本类型
Numbers (int, double)
- int
整数值不大于 64 位,值的范围可以是 -2^63到 2^63 - 1,具体取决于平台
var x = 1;
var hex = 0xDEADBEEF;
- double
64 位(双精度)浮点数
# 可以将变量声明为 num。如果这样做,变量可以同时具有整数和双精度值。
num x = 1; // x can have both int and double values
x += 2.5;
# 必要时,整数字面量会自动转换为双精度数:
double z = 1; // Equivalent to 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');
Strings (String)
可以使用单引号或双引号来创建字符串
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
可以使用 ${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 作为前缀来创建 "原始 "字符串
# 反斜杠 “\” 不会被当作转义字符,而是被当作普通的字符处理
var s = r'In a raw string, not even \n gets special treatment.';
原始字符串文字,是指没有转义字符的字符串,它可以让我们在字符串中不需要对一些特殊字符进行转义,直接使用原始的字符即可
字面字符串是编译时常量,只要任何插值表达式是求值为空或数值、字符串或布尔值的编译时常量即可。
// 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 = [1, 2, 3];
// 有效
const validConstString = '$aConstNum $aConstBool $aConstString';
// 无效
// const invalidConstString = '$aNum $aBool $aString $aConstList';
Booleans (bool)
只有两个对象具有 bool 类型:布尔字面量 true 和 false,它们都是编译时常量
Dart 的类型安全意味着您不能使用 if (nonbooleanValue) 或 assert (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 = null;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Runes (Runes; 经常被 characters API 取代)
如果需要读取或写入单个 Unicode 字符,请使用字符包为 String 定义的字符获取器。返回的 Characters 对象是字符串的字符串簇序列。下面是一个使用字符 API 的示例:
import 'package:characters/characters.dart';
void main() {
var hi = 'Hi 🇩🇰';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}');
}
输出结果如下:
Symbols (Symbol)
符号对象代表 Dart 程序中声明的运算符或标识符。您可能永远都不需要使用符号,但对于通过名称来引用标识符的 API 来说,符号是非常宝贵的,因为最小化会改变标识符名称,但不会改变标识符符号。
#radix
#bar
Foo.dart
library foo_lib;
// libarary name can be a symbol
class Foo {
// class name can be a symbol
m1() {
// method name can be a symbol
print("Inside m1");
}
m2() {
print("Inside m2");
}
m3() {
print("Inside m3");
}
}
以下代码在Symbol类型的帮助下加载Foo.dart库并搜索Foo类。由于需要反射上述库中的元数据,因此这里需要代码导入dart:mirrors库。
import 'dart:core';
import 'dart:mirrors';
import 'Foo.dart';
main() {
Symbol lib = new Symbol("foo_lib");
//library name stored as Symbol
Symbol clsToSearch = new Symbol("Foo");
// class name stored as Symbol
if(checkIf_classAvailableInlibrary(lib, clsToSearch))
// searches Foo class in foo_lib library
print("class found..");
}
bool checkIf_classAvailableInlibrary(Symbol libraryName, Symbol className) {
MirrorSystem mirrorSystem = currentMirrorSystem();
LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName);
if (libMirror != null) {
print("Found Library");
print("checkng...class details..");
print("No of classes found is : ${libMirror.declarations.length}");
libMirror.declarations.forEach((s, d) => print(s));
if (libMirror.declarations.containsKey(className)) return true;
return false;
}
}
注意:代码行 - libMirror.declarations.forEach((s, d) => print(s));将在运行时迭代库中的每个声明,并将声明打印为Symbol的类型。
Found Library
checkng...class details..
No of classes found is : 1
Symbol("Foo") // class name displayed as symbol
class found.
引用:更多请阅读 https://www.yiibai.com/dart/dart_programming_symbol.html#article-start
Records ((value1, value2))
Record syntax
record 表达式是以逗号分隔的命名或位置字段列表,用括号括起来:
var record = ('first', a: 2, b: true, 'last');
record 类型注释是以逗号分隔的类型列表,用括号括起来。您可以使用记录类型注解来定义返回类型和参数类型。例如,以下 (int, int) 语句就是记录类型注解:
(int, int) swap((int, int) record) {
var (a, b) = record;
return (b, a);
}
// Record type annotation in a variable declaration:
(String, int) record;
// Initialize it with a record expression:
record = ('A string', 123);
// Record type annotation in a variable declaration:
({int a, bool b}) record;
// Initialize it with a record expression:
record = (a: 123, b: true);
// 字段名不同类型也不同
({int a, int b}) recordAB = (a: 1, b: 2);
({int x, int y}) recordXY = (x: 3, y: 4);
// Compile error! These records don't have the same type.
// recordAB = recordXY; // no
(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (3, 4);
recordAB = recordXY; // OK.
Record fields
record 是不可变的只有 getter
var record = ('first', a: 2, b: true, 'last');
print(record.$1); // Prints 'first'
print(record.a); // Prints 2
print(record.b); // Prints true
print(record.$2); // Prints 'last'
Record types
单个记录类型没有类型声明。记录是根据其字段类型进行结构类型化的。记录的形状(字段集、字段类型及其名称(如有))唯一地决定了记录的类型。
(num, Object) pair = (42, 'a');
var first = pair.$1; // Static type `num`, runtime type `int`.
var second = pair.$2; // Static type `Object`, runtime type `String`.
Record equality
如果两条记录具有相同的形状(字段集),且相应字段的值相同,则这两条记录是相等的。由于已命名字段的顺序不是记录形状的一部分,因此已命名字段的顺序不会影响相等性。
(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);
print(point == color); // Prints 'true'.
({int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({int r, int g, int b}) color = (r: 1, g: 2, b: 3);
print(point == color); // Prints 'false'. Lint: Equals on unrelated types.
Multiple returns
记录允许函数返回捆绑在一起的多个值。要从返回中检索记录值,请使用模式匹配将值解构为局部变量。
Explain
// Returns multiple values in a record:
(String, int) userInfo(Map<String, dynamic> json) {
return (json['name'] as String, json['age'] as int);
}
final json = <String, dynamic>{
'name': 'Dash',
'age': 10,
'color': 'blue',
};
// Destructures using a record pattern:
var (name, age) = userInfo(json);
/* Equivalent to:
var info = userInfo(json);
var name = info.$1;
var age = info.$2;
*/
Collections
Dart 内置支持 list、set 和 map 集合
Lists (List, also known as arrays)
var list = [1, 2, 3];
var list = [
'Car',
'Boat',
'Plane',
];
To create a list that’s a compile-time constant, add const before the list literal:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // This line will cause an error.
Sets (Set)
Dart 中的集合是由唯一项组成的无序集合。Dart 通过集合文字和集合类型提供对集合的支持。
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
要创建空集,可在类型参数前使用 {},或将 {} 赋值给 Set 类型的变量:
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
使用 add() 或 addAll() 方法将项目添加到现有集合中:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
要创建一个编译时常量的集合,请在集合字面之前添加 const:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // This line will cause an error.
Maps (Map)
Dart 对映射的支持由映射字面意义和映射类型提供。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
// 使用下标赋值操作符([]=)向现有映射添加新的键值对:
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';
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
// 下标取值
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge'); // true
// 不存在返回 null
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null); // true
// length
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
// 要创建一个编译时常量的映射,请在映射字面之前添加 const:
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // This line will cause an error.
扩展运算符
Dart 支持 list、map 和 set 字面中的展开操作符(...)和空感知展开操作符(...?)展开操作符为在集合中插入多个值提供了一种简洁的方法。
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
如果扩展运算符右侧的表达式可能为空,则可以使用空感知扩展运算符(...?)
var list2 = [0, ...?list];
assert(list2.length == 1);
Dart 提供了用于 list、map 和 set 字面的集合 if 和集合 for。您可以使用这些操作符通过条件(if)和重复(for)来构建集合。
var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];
var nav = ['Home', 'Furniture', 'Plants', if (login case 'Manager') 'Inventory'];
var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i']; // ['#0','#1','#2','#3']
assert(listOfStrings[1] == '#1');
泛型
// Object
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
// String
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
// T
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
// 方法和函数也允许使用类型参数:
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
类型定义
typedef IntList = List<int>;
IntList il = [1, 2, 3];
// 类型别名可以有类型参数:
typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // Same thing but shorter and clearer.
typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
assert(sort is Compare<int>); // True!
}