Dart 类型

2023/03/26 Dart 共 5043 字,约 15 分钟
Bob.Zhu

内置类型 Built-in types

Dart 语言对以下内容有特殊支持:

  • Numbers (int, double)
  • Strings (String)
  • Booleans (bool)
  • Lists (List, also known as arrays)
  • Sets (Set)
  • Maps (Map)
  • Runes (Runes; often replaced by the characters API)
  • Symbols (Symbol)
  • The value null (Null)

数字 Numbers

Dart 数字有两种形式:int 和 double。

  • int:不大于 64 位的整数值, 具体取决于平台。
  • double:64 位(双精度)浮点数,由 IEEE 754 标准指定。

字符串 Strings

可以使用单引号或双引号来创建字符串:

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 = '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.';

布尔值 Booleans

Dart有个 bool 的类型,用来表示布尔值。只有两个对象具有 bool 类型:truefalse,他们都是编译时常量。

符文和字素簇 Runes and grapheme clusters

集合 Collections

Lists

在 Dart 中,数组是 List 对象,所以大多数人只是称它们为 lists

// Dart 推断它list具有类型List<int>
var list = [1, 2, 3];

// 可以在最后一项之后添加一个逗号,这个尾随逗号不会影响集合,但它可以帮助防止复制粘贴错误。
var list = [
  'Car',
  'Boat',
  'Plane',
];

// 第一个值的索引:0
// 数组长度:list.length
// 最后一个值的索引:list.length - 1
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

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

// 使用`const`表示编译时常量的列表:
var constantList = const [1, 2, 3];

扩展运算符 Spread operators

Dart 支持扩展运算符...,可以方便地将多个值插入集合:

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

如果扩展运算符右侧的表达式可能为 null,则可以通过使用 null-aware 扩展运算符 ...? 来避免异常:

var list2 = [0, ...?list];
assert(list2.length == 1);

更多参考:Spread Collections

集合运算符 Collection operators

下面是一个使用collection if 来创建包含三个或四个项目的列表的示例:

var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];

下面是在将列表项添加到另一个列表之前使用collection for操作列表项的示例:

var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
assert(listOfStrings[1] == '#1');

更多参考:Control Flow Collections

Sets

不重复的无序集合:

// 创建集合文字
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
// 要创建空集,请{}在类型参数前面使用,或分配{}给类型变量Set:
var names = <String>{};
Set<String> names = {}; 
// var names = {}; // Creates a map, not a set.

// 添加元素或者集合
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
// elements.length 属性获取长度
assert(elements.length == 5);

// 编译时常量:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // 会报错,常量不能修改

问题:

  • 扩展操作符和使用addAll() 方法有什么区别?
  • 是否不同于Java常量,Java中的常量可以修改的

Maps

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

// 添加一个新值:
gifts['fourth'] = 'calling birds'; // Add a key-value pair
// 获取key对应的值:
assert(gifts['first'] == 'partridge');
// 如果不存在,则返回null
assert(gifts['fifth'] == null);
// 同样可以使用 `.length`:
assert(gifts.length == 2);
// 添加const表示编译时常量:
final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

类型别名 Typedefs

下面是声明和使用名为 IntList 的类型别名的示例:

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。但是,函数 typedef 仍然有用:

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!
}

范型 Generics

为什么使用范型

泛型通常是类型安全所必需的,但泛型比仅允许您的代码运行有更多好处:

  • 正确指定泛型类型会生成更好的代码。
  • 您可以使用泛型来减少代码重复。

在下面的代码中,T 是替代类型。它是一个占位符,您可以将其视为开发人员稍后定义的类型。

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

使用集合字面量

var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};

参数化类型与构造函数一起使用

要在使用构造函数时指定一种或多种类型,请将类型放在<…>类名后面的尖括号 ( ) 中。例如:

var nameSet = Set<String>.from(names);
// 以下代码创建一个具有整数键和视图类型值的映射:
var views = Map<int, View>();

通用集合及其包含的类型

Dart 泛型类型是具体化的,这意味着它们在运行时携带它们的类型信息。例如,您可以测试集合的类型:

var names = <String>[];
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true

注意:这里和Java是不一样的,Java的范型在运行期间是会进行擦除的。在 Java 中,你可以测试一个对象是否是一个 List,但你不能测试它是否是一个List.

限制参数化类型

和Java相同,可以使用extends关键字进行限制。 Object 一个常见的用例是通过使类型成为(而不是默认的)的子类型来确保类型不可为空Object?

class Foo<T extends Object> {
  // Any type provided to Foo for T must be non-nullable.
}

使用通用方法

方法和函数也允许类型参数:

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;
}

first这里( )上的泛型类型参数允许您在多个地方使用类型参数:T

  • 在函数的返回类型 ( T) 中。
  • 在参数类型 ( List) 中。
  • 在局部变量 ( ) 的类型中T tmp。

Dart类型系统 type system

参考资料

文档信息

Search

    Table of Contents