Skip to content

以下是您提供的Dart语言文档的完整中文翻译:


Dart是一种面向对象的语言,支持基于类的继承和混入(mixin)机制。每个对象都是某个类的实例,除Null外所有类都继承自Object。基于混入的继承意味着:虽然每个类(除了顶级类Object)有且仅有一个超类,但一个类的主体可以在多个类层次结构中被复用。扩展方法(Extension methods)允许在不修改原类或创建子类的情况下为类添加功能。类修饰符(Class modifiers)可控制库如何对类进行子类型化。


使用类成员

对象由函数和数据(分别为方法和实例变量)组成的成员构成。调用方法时需在对象上调用:该方法可访问该对象的函数和数据。

使用点号(.)访问实例变量或方法:

dart
var p = Point(2, 2);

// 获取y值
assert(p.y == 2);

// 在p上调用distanceTo()方法
double distance = p.distanceTo(Point(4, 4));

使用?.替代.可避免左操作数为null时的异常:

dart
// 若p非null,将它的y值赋给变量
var a = p?.y;

使用构造函数

可通过构造函数创建对象。构造函数名称可以是ClassNameClassName.identifier。例如:

dart
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

也可使用可选的new关键字(效果相同):

dart
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});

某些类提供常量构造函数。使用const关键字创建编译时常量:

dart
var p = const ImmutablePoint(2, 2);

构造两个相同的编译时常量会产生单一规范实例:

dart
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // 它们是同一实例!

在常量上下文中可省略构造函数或字面量前的const

dart
// 多个const关键字(完整写法)
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

// 仅保留第一个const建立常量上下文(推荐写法)
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

若常量构造函数在非常量上下文中且未使用const调用,则创建非常量对象:

dart
var a = const ImmutablePoint(1, 1); // 创建常量
var b = ImmutablePoint(1, 1);       // 不创建常量
assert(!identical(a, b));           // 非同一实例!

获取对象类型

运行时可通过ObjectruntimeType属性获取对象类型(返回Type对象):

dart
print('The type of a is ${a.runtimeType}');

⚠️ 警告:建议使用类型测试操作符而非runtimeType来检测对象类型。生产环境中Type测试比object.runtimeType == Type更稳定。


实例变量

声明实例变量示例:

dart
class Point {
  double? x; // 可空类型,默认null
  double? y; // 可空类型,默认null
  double z = 0; // 非可空类型,显式初始化
}

未初始化的可空类型实例变量默认值为null。非可空实例变量必须在声明时初始化。

所有实例变量会隐式生成getter方法。非final或带late修饰的final实例变量(无初始化器)还会生成setter方法。

初始化非late实例变量时,其值在实例创建时(构造函数及初始化列表执行前)即被设置,因此初始化表达式不能访问this

dart
double initialX = 1.5;

class Point {
  double? x = initialX; // 合法
  double? y = this.x;   // 错误!非late初始化器不能访问this
  late double? z = this.x; // 合法!late初始化器可访问this
  Point(this.x, this.y);   // 合法!构造函数参数不是表达式
}

final实例变量必须且只能被赋值一次,可通过声明时初始化、构造函数参数或初始化列表设置:

dart
class ProfileMark {
  final String name;
  final DateTime start = DateTime.now(); // 直接初始化

  ProfileMark(this.name);                  // 构造函数参数初始化
  ProfileMark.unnamed() : name = '';       // 初始化列表初始化
}

若需在构造函数体开始后赋值final实例变量,可使用:

  • 工厂构造函数
  • late final(注意:无初始化器的late final会向API添加setter)

隐式接口

每个类都隐式定义了一个包含自身所有实例成员及所实现接口的接口。若想让类A支持类B的API但不继承其实现,应让A实现B的接口:

dart
// 定义隐式接口(含greet()方法)
class Person {
  final String _name;
  Person(this._name);
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// 实现Person接口
class Impostor implements Person {
  String get _name => '';
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

实现多个接口示例:

dart
class Point implements Comparable, Location { ... }

类变量和方法

使用static关键字定义类范围的变量和方法。

静态变量

用于类级别的状态和常量:

dart
class Queue {
  static const initialCapacity = 16;
}

void main() {
  assert(Queue.initialCapacity == 16);
}

注意:静态变量在使用时才会初始化。常量命名建议使用lowerCamelCase风格。

静态方法

不操作实例,因此无法访问this,但可访问静态变量。通过类名直接调用:

dart
import 'dart:math';

class Point {
  double x, y;
  Point(this.x, this.y);

  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

建议:对于通用工具功能,优先使用顶层函数而非静态方法。静态方法可作为编译时常量使用(如传递给常量构造函数)。