MirrorYuChen
MirrorYuChen
Published on 2025-08-20 / 7 Visits
0
0

Flutter入门学习笔记(三):dart核心语法

Flutter入门学习笔记(三):dart核心语法

1.导库方法

​ 简单来说,通过 import将别的库拿来用,基础语法为:

import 'uri' [as alias] [show/hide id] [deferred]

1.1 基础用法

// 1.引入系统库math
import 'dart:math';
// 2.引入自己的文件
import 'utils/string_helper.dart';  // 相对路径
import '/src/models/user.dart';     // 绝对路径(从项目根目录开始)
// 3.引入第三方包(pub上的)
import 'package:http/http.dart';   // 前缀package表示来自.packages映射
// 4.使用as引入同时起别名,解决名字冲突
import 'package:collection/collection.dart' as coll;
void main() {
  coll.DeepCollectionEquality eq = coll.DeepCollectionEquality();
}

1.2 按需取用

​ 使用 show/hide只取部分:

import 'dart:math' show pi, cos;  // 只导入pi和cos
import 'dart:math' hide Random;   // 除了Random,其余都导入

1.3 懒加载

​ 延迟加载,直至真正需要时再下载/加载:

import 'package:charts_flutter/flutter.dart' deferred as charts;

Future<void> showChart() async {
  await charts.loadLibrary();      // 真正需要时再下载/加载
  charts.BarChart(...);
}

1.4 大库拆分

​ 使用 part/part of将大库拆成多个文件:

  • (1) 主库文件 lib/my_lib.dart
/*
 * @Author: chenjingyu
 * @Date: 2025-08-20 09:51:35
 * @Contact: 2458006466@qq.com
 * @Description: my_lib
 */
// 声明这是一个库,名字叫 my_lib
library my_lib;

// 把两个“子文件”合进来
part 'src/math_utils.dart';
part 'src/string_utils.dart';

// 主库里也可以写自己的代码
int sum(int a, int b) => a + b;
  • (2) 子文件 lib/src/math_utils.dart中:
/*
 * @Author: chenjingyu
 * @Date: 2025-08-20 09:52:15
 * @Contact: 2458006466@qq.com
 * @Description: math_utils
 */
// 必须指明属于哪个库
part of my_lib;

int multiply(int a, int b) => a * b;
  • (3) 子文件 lib/src/string_utils.dart中:
/*
 * @Author: chenjingyu
 * @Date: 2025-08-20 09:52:22
 * @Contact: 2458006466@qq.com
 * @Description: string_utils
 */
part of my_lib;

String greet(String name) => 'Hello, $name!';
  • (4) 可执行文件 bin/my_lib.dart中:
/*
 * @Author: chenjingyu
 * @Date: 2025-08-20 09:51:35
 * @Contact: 2458006466@qq.com
 * @Description: my_lib
 */
import 'package:my_lib/my_lib.dart' as my;

void main() {
  print(my.sum(2, 3)); // 来自主库
  print(my.multiply(4, 5)); // 来自 math_utils.dart
  print(my.greet('Mirror')); // 来自 string_utils.dart
}

​ 运行:

>>  dart run
Building package executable...
Built my_lib:my_lib.
5
20
Hello, Mirror!

2.类和对象

​ Dart 是一门面向对象语言,支持类(class)以及基于混入(mixin)的继承机制。

  • 每一个对象都是某个类的实例,除 Null 之外的所有类最终都继承自 Object
  • “基于混入的继承”指的是:除最顶层的 Object(或 Object?)外,每个类有且仅有一个直接父类,但一个类体可以通过混入,从而被多个不同的类层次复用。
  • 扩展方法(extension methods)允许在不修改原类、也不创建子类的情况下,为其添加新功能。
  • 类修饰符(class modifiers)则让你可以控制其他库能否对该类进行子类化(subtyping)。

2.1 类成员访问

​ 对象有两种成员:函数和数据(分别对应成员方法和成员变量)。我们可以使用 .来访问一个实例的成员变量或成员方法:

var p = Point(2, 2);

// 1.获取p的成员变量y值
assert(p.y == 2);

// 2.调用p的成员方法distanceTo
double  distance = p.distanceTo(Point(4, 4));

​ 使用 ?.代替 .来避免当左侧操作数为 null时抛出异常:

// 如果p非空,将变量a设置为其y值
var a = p?.y;

2.2 使用构造函数

​ 你可以使用构造函数来创建一个对象。构造函数名可以是 ClassNameClassName.identifier。例如:

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

​ 以下代码具有相同效果,但使用可选的 new关键字在构造函数名前:

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

​ 某些类提供常量构造函数,构造两个相同编译时常量会得到单一的实例:

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!

​ 你可以使用 Object属性 runtimeType来在运行时获取对象类型:

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

2.3 实例变量

​ 使用可空类型声明的未初始化变量值为 null,非空实例变量必须在声明是初始化。所有实例变量都会生成一个隐式 getter方法。非 final实例和没有初始化的 late/final实例变量也会生成一个隐式的 setter方法。

class Point {
  double? x; // 可空变量x,初始化为null
  double? y; // 可空变量y,初始化为null
}

void main() {
  var point = Point();
  point.x = 4;             // 对x使用setter方法.
  assert(point.x == 4);    // 对x使用getter方法.
  assert(point.y == null); // 值的默认值为null.
}

​ 在声明处初始化非 late实例变量会在实例创建时赋值,这发生在构造函数及其初始化列表执行之前。因此,非 late实例变量的初始化表达式不能访问 this

double initialX = 1.5;

class Point {
  // OK, initialX不依赖于this,可以访问:
  double? x = initialX;

  // ERROR, y不是late标记,不能访问this:
  double? y = this.x;

  // OK, z为late标记,可以访问this
  late double? z = this.x;

  // OK, `this.x`和`this.y`是参数声明,不是表达式
  Point(this.x, this.y);
}

2.4 静态变量和讲台方法

​ 静态变量在使用前不会被初始化,对于类范围的状态和常量非常有用。

class Queue {
  static const initialCapacity = 16;
  // ···
}

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

​ 静态方法(类方法)不作用于实例,因此无法访问 this。但是,它们可以访问静态变量。

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

2.5 构造函数

  • (1) 生成式构造函数

​ 创建新实例并初始化实例变量。

class Point {
  // 存储点坐标的实例变量
  double x;
  double y;

  // 生成式构造函数初始化实例变量
  Point(this.x, this.y);
}
  • (2) 默认构造函数

​ 当没有指定构造函数时,用于创建新实例。它不接受参数且没有名称。

class Point {
  double? x;
  double? y;
}

void main() {
  final p = Point();
  print(p);
}
  • (3) 命名构造函数

​ 使用命名构造函数可以为一个类实现多个构造函数,或提供额外的清晰度。

const double xOrigin = 0;
const double yOrigin = 0;

class Point {
  final double x;
  final double y;

  // Sets the x and y instance variables
  // before the constructor body runs.
  Point(this.x, this.y);

  // Named constructor
  Point.origin() : x = xOrigin, y = yOrigin;
}

​ 子类不继承超类的命名构造函数,要在子类中创建超类中定义的命名构造函数,请在子类中实现该构造函数。

  • (4) 常量构造函数

​ 若类产生不可变对象,请将这些对象设为编译时常量。要使对象成为编译时常量,请定义一个 const 构造函数,并将所有实例变量设置为 final

class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}
  • (5) 重定向构造函数

​ 构造函数可以将调用重定向到同一类的另一个构造函数。重定向构造函数没有函数体。构造函数在冒号 (:) 后使用 this 而不是类名。

class Point {
  double x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(double x) : this(x, 0);
}
  • (6) 工厂构造函数

​ 在实现构造函数时遇到以下两种情况之一时,使用 factory 关键字

  • 构造函数并不总是创建其类的新实例。尽管工厂构造函数不能返回 null,但它可能会返回
    • 缓存中的现有实例,而不是创建新实例
    • 子类的新实例
  • 在构造实例之前需要执行非平凡的工作。这可能包括检查参数或执行初始化列表中无法处理的任何其他处理。
class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache = <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

2.6 方法

​ 方法是为对象提供行为的函数。

  • (1) 实例方法

​ 对象上的实例方法可以访问实例变量和 this

import 'dart:math';

class Point {
  final double x;
  final double y;

  // Sets the x and y instance variables
  // before the constructor body runs.
  Point(this.x, this.y);

  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}
  • (2) 运算符

大多数运算符是具有特殊名称的实例方法。Dart 允许您定义以下名称的运算符:

< > <= >= == ~
- + / ~/ * %
` ` ˆ & << >>>
[]= []
class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  @override
  bool operator ==(Object other) =>
      other is Vector && x == other.x && y == other.y;

  @override
  int get hashCode => Object.hash(x, y);
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}
  • (3) getter和setter
class Rectangle {
  double left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  double get right => left + width;
  set right(double value) => left = value - width;
  double get bottom => top + height;
  set bottom(double value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}
  • (4) 抽象方法

​ 实例、Getter 和 Setter 方法可以是抽象的,它们定义了一个接口,但将其实现留给其他类。抽象方法只能存在于抽象类混入中。要使一个方法成为抽象方法,请使用分号 (;) 代替方法体

abstract class Doer {
  // Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // Provide an implementation, so the method is not abstract here...
  }
}

3.参考资料


Comment