Flutter入门:Flutter开发必备Dart基础

Flutter之Dart常用数据类型(数字、类型转换)

1. Dart 数字类型简介

类型 说明 备注
int 64位整数 适合整数,索引、计数等场景
double 64位浮点数(双精度) 适合小数、精确度要求不高的场景
num intdouble 的父类 接受整数和浮点数的通用类型
BigInt 任意大小整数 用于超大整数计算或加密等场景

2. 数字变量示例

dart 复制代码
int a = 100;
double b = 3.1415;
num c = 50;       // 也可以赋 int 或 double
num d = 2.718;
BigInt big = BigInt.parse('123456789012345678901234567890');

3. 数字运算示例

dart 复制代码
int x = 10;
double y = 3.5;

var sum = x + y;      // 13.5,结果是 double
var div1 = x / 3;     // 3.3333 double
var div2 = x ~/ 3;    // 3,整数除法,舍弃小数部分

print(x.isEven);     // true
print(y.round());    // 4 四舍五入
print(y.floor());    // 3 向下取整
print(y.ceil());     // 4 向上取整

4. 类型转换

int 与 double 互转

dart 复制代码
int i = 5;
double d = i.toDouble();   // int -> double

double e = 3.7;
int j = e.toInt();         // double -> int(直接截断)
int k = e.round();         // 四舍五入
int l = e.floor();         // 向下取整
int m = e.ceil();          // 向上取整

BigInt 与 int 互转

dart 复制代码
BigInt bigInt = BigInt.from(123456789);
int normalInt = bigInt.toInt();   // 可能溢出,慎用

5. 字符串与数字的转换

字符串转数字

dart 复制代码
int x = int.parse('123');
double y = double.parse('3.14');

int? maybeInt = int.tryParse('abc');  // 解析失败返回 null

数字转字符串

dart 复制代码
String s1 = 123.toString();              // "123"
String s2 = 3.14159.toStringAsFixed(2); // "3.14" 保留两位小数
String s3 = 255.toRadixString(16);      // "ff" 转16进制字符串

6. 其它常用小技巧

  • 使用 num 类型时要注意,部分方法不同,如 ~/ 只能用于整数类型。
  • BigInt 不能直接与 intdouble 混合运算,需转换后再操作。
  • tryParse 可避免因格式错误导致程序异常崩溃。

7. 总结

操作 关键函数/方法 备注
整数与浮点转换 toDouble(), toInt(), round() 常用转换方式
字符串转数字 int.parse(), double.parse(), tryParse() 容错推荐用 tryParse
数字转字符串 toString(), toStringAsFixed(), toRadixString() 格式化输出
大整数处理 BigInt.parse(), BigInt.from() 用于大数及加密计算

Flutter之Dart常用数据类型(字符串)

1. Dart 中字符串的基本介绍

  • 类型String,表示一串 UTF-16 编码的字符序列。

  • 特点

    • 不可变(immutable),即字符串内容不可更改,修改会生成新字符串。
    • 支持单引号 '...' 或双引号 "..." 定义。
    • 支持多行字符串,使用三引号 '''...'''"""..."""

2. 字符串声明示例

dart 复制代码
String s1 = 'Hello, Dart!';
String s2 = "Hello, Flutter!";
String s3 = '''这是
一个多行
字符串''';

String s4 = """另一种
多行
字符串""";

3. 字符串拼接

dart 复制代码
String a = 'Hello';
String b = 'World';

String c = a + ' ' + b;            // 使用 + 连接
String d = '$a $b';                // 使用字符串插值
String e = '${a.toUpperCase()} $b'; // 表达式插值

4. 字符串常用操作方法

方法 说明 示例
length 字符串长度 'abc'.length // 3
isEmpty / isNotEmpty 是否为空 ''.isEmpty // true
toUpperCase() 转大写 'abc'.toUpperCase() // 'ABC'
toLowerCase() 转小写 'ABC'.toLowerCase() // 'abc'
contains() 是否包含子串 'hello'.contains('ll') // true
startsWith() 是否以指定字符串开头 'hello'.startsWith('he') // true
endsWith() 是否以指定字符串结尾 'hello'.endsWith('lo') // true
substring(start, [end]) 截取子串 'hello'.substring(1,4) // 'ell'
indexOf() 查找子串第一次出现的位置 'hello'.indexOf('l') // 2
lastIndexOf() 查找子串最后一次出现的位置 'hello'.lastIndexOf('l') // 3
replaceAll() 替换所有匹配子串 'hello'.replaceAll('l', 'x') // 'hexxo'
split() 按分隔符拆分字符串成列表 'a,b,c'.split(',') // ['a','b','c']
trim() 去除首尾空白 ' hello '.trim() // 'hello'

5. 字符串插值与表达式

dart 复制代码
String name = 'Alice';
int age = 30;

String greeting = 'Hello, $name. You are $age years old.';
String complex = 'Next year you will be ${age + 1} years old.';

6. 多行字符串和原始字符串(Raw String)

  • 多行字符串:
dart 复制代码
String multiLine = '''
这是一个
多行字符串
示例。
''';
  • 原始字符串(不转义 ``):
dart 复制代码
String raw = r'In a raw string, \n is not special.';

7. 常用转义字符

转义符 说明 示例
' 单引号 'It's OK'
" 双引号 "She said "Hi""
\ 反斜杠 'C:\Path'
\n 换行 'Line1\nLine2'
\t 制表符 'Column1\tColumn2'

8. 字符串编码与解码(简单示例)

dart 复制代码
import 'dart:convert';

String text = 'Hello, Dart!';
List<int> utf8Bytes = utf8.encode(text);      // 编码为 UTF8 字节
String decoded = utf8.decode(utf8Bytes);     // 解码回字符串

9. 字符串和字符

  • Dart 没有专门的 char 类型,单个字符用字符串的单字符表示。
dart 复制代码
String char = 'A';  // 单字符字符串
print(char.length); // 1

10. 示例:统计字符串中某字符出现次数

dart 复制代码
String str = "banana";
int count = str.split('a').length - 1;  // 计算 'a' 出现次数
print(count);  // 输出 3

Flutter之Dart常用数据类型(布尔、List)

1. 布尔类型(bool)

基础介绍

  • Dart 中布尔类型用 bool 表示,只有两个值:truefalse
  • 常用于条件判断、循环控制、开关标志等。

示例

dart 复制代码
bool isActive = true;
bool isDone = false;

if (isActive) {
  print('激活状态');
} else {
  print('未激活');
}

常用逻辑运算符

运算符 说明 示例
! 取反(NOT) !isActive
&& 逻辑与(AND) isActive && isDone
` `

2. 列表类型(List)

基础介绍

  • List 是 Dart 中的有序集合,类似数组。
  • 可以存储相同类型或混合类型的元素(如果未指定泛型)。
  • 支持动态长度,也可以声明为固定长度。

声明方式

dart 复制代码
// 泛型指定为int
List<int> numbers = [1, 2, 3, 4];

// 类型自动推断
var fruits = ['apple', 'banana', 'orange'];

// 空列表
List<String> emptyList = [];

// 固定长度列表
var fixedList = List.filled(3, 0); // 长度3,初始值0

常用操作

dart 复制代码
var list = [10, 20, 30];

// 访问元素
print(list[0]);   // 10

// 修改元素
list[1] = 25;

// 添加元素
list.add(40);

// 插入元素
list.insert(1, 15);

// 删除元素
list.remove(30);
list.removeAt(0);

// 列表长度
print(list.length);

// 遍历列表
for (var item in list) {
  print(item);
}

常用方法总结

方法 说明
add(value) 在末尾添加元素
insert(index, value) 在指定位置插入元素
remove(value) 删除首次出现的指定元素
removeAt(index) 删除指定位置元素
clear() 清空列表
contains(value) 判断是否包含指定元素
indexOf(value) 查找元素首次出现的索引
sort() 对列表排序
reversed 返回元素反转后的 Iterable

3. 结合示例

dart 复制代码
bool isLoggedIn = false;
List<String> messages = [];

if (!isLoggedIn) {
  messages.add('请先登录');
}

messages.add('欢迎回来!');

for (var msg in messages) {
  print(msg);
}

Flutter之Dart常用数据类型(Map)

1. Map 基础介绍

  • Map 是键值对(key-value)集合,也称为字典或哈希表。
  • 每个键对应一个值,键不允许重复,值可以重复。
  • 键和值的类型可以是任意类型,但通常键是 String 或基本类型。
  • Dart 的 Map 是无序的,若需要有序的 Map 可用 LinkedHashMap

2. Map 声明与初始化

dart 复制代码
// 空 Map,键和值都为 String
Map<String, String> capitals = {};

// 直接初始化
var countries = {
  'USA': 'Washington, D.C.',
  'Japan': 'Tokyo',
  'China': 'Beijing',
};

// 使用构造函数创建空 Map
var emptyMap = Map<String, int>();

// 也可以用 var,类型由内容推断
var scores = {'Alice': 90, 'Bob': 85, 'Cindy': 92};

3. Map 常用操作

dart 复制代码
var map = {'apple': 3, 'banana': 5};

// 访问
print(map['apple']);      // 3
print(map['orange']);     // null,如果key不存在

// 修改或添加
map['apple'] = 4;         // 修改
map['orange'] = 7;        // 新增

// 删除
map.remove('banana');

// 判断是否包含key或value
print(map.containsKey('apple'));   // true
print(map.containsValue(7));       // true

// 获取所有key和value
print(map.keys);   // (apple, orange)
print(map.values); // (4, 7)

// 清空
map.clear();

4. 遍历 Map

方式一:遍历键值对

dart 复制代码
var map = {'a': 1, 'b': 2};

map.forEach((key, value) {
  print('$key -> $value');
});

方式二:遍历 key 或 value 列表

dart 复制代码
for (var key in map.keys) {
  print('Key: $key');
}

for (var value in map.values) {
  print('Value: $value');
}

5. Map 与 JSON 互转(常见场景)

Flutter 常用 Map<String, dynamic> 来表示 JSON 对象。

dart 复制代码
import 'dart:convert';

String jsonString = '{"name":"Alice","age":25}';

// JSON字符串转Map
Map<String, dynamic> user = json.decode(jsonString);

// Map转JSON字符串
String jsonStr = json.encode(user);

print(user['name']);  // Alice

6. 总结

操作 方法/语法 说明
创建 Map {}Map() 声明空或初始化 Map
访问元素 map[key] 通过 key 访问值
添加/修改元素 map[key] = value 新增或修改元素
删除元素 map.remove(key) 删除指定 key 的元素
判断包含 containsKey(key) 是否存在指定 key
遍历 forEach(), for...in 遍历 key-value 或 keys/values

dynamic、var、Object的使用与区别

1. var

  • 含义:由编译器根据赋值自动推断变量类型。

  • 特点

    • 类型一旦推断确定,变量类型固定,后续赋值必须是相同类型。
    • 不能重新赋不同类型的值,否则编译错误。

示例

dart 复制代码
var x = 10;    // x 是 int 类型
x = 20;        // 合法
// x = 'hello';  // 编译错误,不能赋值 String 给 int 类型的变量
  • 如果没有初始化,var 就不能推断类型,必须显式声明类型:
dart 复制代码
var y;         // 编译错误,必须初始化或指定类型
int y;         // 正确,声明未初始化的 int 变量

2. dynamic

  • 含义:动态类型,关闭类型检查。

  • 特点

    • 赋值后变量类型可以随时改变。
    • 编译时不检查调用的方法和属性,运行时才会报错(类似弱类型语言)。
    • 灵活但风险较高,易出现运行时错误。

示例

dart 复制代码
dynamic a = 10;
a = 'hello';        // 合法,动态类型可以改变
a.someUndefinedMethod(); // 编译不报错,运行时才会出错

3. Object

  • 含义:所有 Dart 对象的基类(顶层父类)。

  • 特点

    • 编译器会检查方法和属性调用是否合法(需类型转换)。
    • 赋值可以是任何类型,但访问方法时需类型断言或转换。
    • dynamic 更安全,但比 var 更通用。

示例

dart 复制代码
Object obj = 10;
obj = 'hello';

// 不能直接调用字符串方法
// obj.length; // 编译错误

// 需先转换类型
if (obj is String) {
  print(obj.length); // 合法
}

4. 三者对比总结

特性 var dynamic Object
类型推断 编译时根据初始值推断固定类型 动态类型,无类型检查 编译时类型为 Object
类型安全 类型安全,后续赋值必须相同类型 不安全,任何类型均可赋值,调用不报错 相对安全,调用时需类型转换
访问成员 可调用变量实际类型的方法和属性 任何方法都可调用,运行时可能异常 只能调用 Object 定义的方法,需强转访问
赋值 必须符合推断类型 可随意更改类型 可赋任何类型,但限制访问

总结:

  • dynamicObject 最大的区别是:
    dynamic 关闭了静态类型检查,Object 则有静态类型检查。

5. 适用场景

类型 使用场景
var 普通变量声明,类型已知且确定,推荐使用
dynamic 需要完全动态、灵活的场景,如解析未知结构的数据、反射等
Object 需要通用类型但保持一定安全性时,作为基类引用使用

6. 示例代码综合比较

dart 复制代码
void main() {
  var x = 10;
  // x = 'hello'; // 编译错误

  dynamic y = 10;
  y = 'hello';    // 合法
  // y.noSuchMethod(); // 运行时错误,编译不报错

  Object z = 10;
  z = 'hello';
  // print(z.length); // 编译错误,需转换
  if (z is String) {
    print(z.length); // 合法,输出5
  }
}

Flutter中常用的Dart方法类型

方法的构成:返回值类型 + 方法名 + 参数

  • 返回值类型

    • 可以省略,默认是 void,也可以是具体类型如 intString 等。为了规范,一般有具体返回值的都需要写
  • 方法名

    • 匿名方法不需要方法名,这时调用时会用变量名或上下文来引用。
  • 参数

    • 包含参数类型和参数名。
    • 参数类型可省略,Dart 允许类型推断。
    • 参数可以是必选参数,也可以是可选参数(带默认值)。
    • 参数支持位置可选参数和命名可选参数。

1. 入口方法(main)

dart 复制代码
void main() {
  print('程序入口');
}

2. 实例方法

dart 复制代码
class Person {
  String name;

  Person(this.name);

  void greet() {
    print('Hello, $name');
  }
}

var p = Person('Alice');
p.greet();  // Hello, Alice

3. 私有方法

前边加下划线表示私有,用于方法、变量等。

dart 复制代码
class Example {
  void publicMethod() {
    _privateMethod();
  }

  void _privateMethod() {
    print('这是私有方法,只能在本库访问');
  }
}

var e = Example();
e.publicMethod();  // 可以调用私有方法间接访问
// e._privateMethod(); // 外部调用会报错

4. 匿名方法

dart 复制代码
var list = [1, 2, 3];
list.forEach((item) {
  print(item * 2);
});
// 输出 2,4,6

5. 静态方法

dart 复制代码
class MathUtil {
  static int add(int a, int b) => a + b;
}

print(MathUtil.add(3, 4));  // 7

6. 构造方法

dart 复制代码
class Point {
  int x, y;

  Point(this.x, this.y);  // 构造方法
}

var pt = Point(10, 20);
print('${pt.x}, ${pt.y}');  // 10, 20

7. setters 和 getters

dart 复制代码
class Rectangle {
  double _width = 0, _height = 0;

  double get area => _width * _height;

  set width(double w) => _width = w;
  set height(double h) => _height = h;
}

var rect = Rectangle();
rect.width = 5;
rect.height = 10;
print(rect.area);  // 50

8. 抽象方法

dart 复制代码
abstract class Animal {
  void speak();  // 抽象方法,子类必须实现
}

class Dog extends Animal {
  @override
  void speak() {
    print('汪汪');
  }
}

var dog = Dog();
dog.speak();  // 汪汪

9. 泛型方法

dart 复制代码
T echo<T>(T value) {
  return value;
}

print(echo<int>(123));     // 123
print(echo<String>('Hi')); // Hi

Flutter中的面向对象(标准构造方法、初始化列表与命名构造方法)

1. 标准构造方法(Default Constructor)

  • 最常用的构造函数,直接用类名定义。
  • 可带参数,常用于初始化对象属性。

示例

dart 复制代码
class Person {
  String name;
  int age;

  // 标准构造方法
  Person(this.name, this.age);
}

var p = Person('Alice', 30);
print(p.name);  // Alice

2. 初始化列表(Initializer List)

  • 用于在构造函数体执行前初始化字段。
  • 可以做一些复杂的计算、断言等。
  • 初始化列表在冒号 : 后,构造函数体 {} 前。

示例

dart 复制代码
class Point {
  final int x;
  final int y;
  final double distance;

  // 初始化列表计算 distance
  Point(this.x, this.y) 
    : distance = (x * x + y * y).toDouble().sqrt();
}

var pt = Point(3, 4);
print(pt.distance);  // 5.0

注意:

Dart 标准库里 sqrt()dart:math 里,用法如下:

dart 复制代码
import 'dart:math';

Point(this.x, this.y) : distance = sqrt(x * x + y * y);

3. 命名构造方法(Named Constructor)

  • 语法:ClassName.constructorName(...),前面factory

  • 在初始化列表里或构造体中,直接给 final 字段赋值。

  • 只能返回自身的新实例。

  • 补充 :除了普通命名构造,也可以写重定向构造

    dart 复制代码
    Point.zero() : this(0, 0);

示例

dart 复制代码
class Person {
  String name;
  int age;

  // 标准构造方法
  Person(this.name, this.age);

  // 命名构造方法,默认年龄
  Person.withNameOnly(this.name) : age = 18;

  // 命名构造方法,工厂构造
  Person.guest() {
    name = 'Guest';
    age = 0;
  }
}

var p1 = Person('Alice', 30);
var p2 = Person.withNameOnly('Bob');
var p3 = Person.guest();

print(p2.age);  // 18
print(p3.name); // Guest

4. 工厂构造方法

类似于java中的单例实现。

  • 严格说,这也是 factory 构造,只不过常见用例是单例模式

    dart 复制代码
    class Logger {
      factory Logger() => _instance ??= Logger._();
      static Logger? _instance;
      Logger._();
    }
  • 但它的能力不止单例:

    • 缓存已有对象
    • 抽象类返回具体子类
    • JSON、数据库等场景下的"解析工厂"
  • 补充 :任何带 factory 关键字的构造都属于"工厂构造",命名或未命名都行。

dart 复制代码
class Logger {
  static final Map<String, Logger> _cache = {};

  final String name;

  // 工厂构造方法,返回缓存实例
  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name]!;
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    print('[$name] $msg');
  }
}

var logger1 = Logger('UI');
var logger2 = Logger('UI');

print(logger1 == logger2);  // true,返回同一个实例

5. 命名工厂构造方法

  • 语法:在命名构造方法前加 factory,形如 factory ClassName.name(...)

  • 不能 使用初始化列表(因此不能直接给 final 字段赋值),只能在函数体里 return 一个实例。

  • 可返回已缓存的实例、子类实例,甚至在抽象类中返回具体实现。

  • 补充 :factory 构造方法不能声明为 const

dart 复制代码
class Shape {
  factory Shape.circle(double radius) => Circle(radius);
  factory Shape.square(double size) => Square(size);
}

class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

class Square implements Shape {
  final double size;
  Square(this.size);
}

var circle = Shape.circle(5);
var square = Shape.square(10);

// 命名工厂构造方法返回不同子类
class Shape {
  factory Shape.circle(double radius) => Circle(radius);
  factory Shape.square(double size) => Square(size);
}

总结

关键点 说明
标准构造方法 类名作为函数名,简单初始化字段
初始化列表 在构造体执行前初始化字段或计算属性
命名构造方法 多个构造方法,提供灵活的初始化途径,返回值 自身新实例 可以为const,常用于 参数多样的初始化
工厂构造方法 使用 factory 关键字声明,不一定返回新实例,可返回已有实例,常用于缓存和控制实例创建
命名工厂构造方法 带名字的工厂构造方法,支持多种工厂创建方案,封装复杂初始化逻辑,返回多种类型对象,可返回已有实例、子类、null,不能是const,缓存/单例/多态工厂/抽象工厂

Dart的get和set方法

在 Dart 中,getset 关键字用来定义属性访问器,让我们可以像访问字段一样调用方法,同时还可以在读取或写入时添加自定义逻辑。l类似于java中的getter与setter。


1. 基本语法

dart 复制代码
class Person {
  String _name; // 私有字段,下划线表示私有

  // Getter:无参数,返回类型可省略或写具体类型
  String get name => _name;

  // Setter:单参数,返回值必须是 void
  set name(String value) {
    _name = value;
  }

  Person(this._name);
}

使用方式:

dart 复制代码
var p = Person('Alice');
print(p.name);   // 调用 getter,输出 "Alice"
p.name = 'Bob';  // 调用 setter
print(p.name);   // 输出 "Bob"

2. 只读或只写属性

  • 只读 :只定义 get,不提供 set(外部无法赋值)
  • 只写 :只定义 set,不提供 get(外部无法读取)
dart 复制代码
class Counter {
  int _count = 0;

  // 只读
  int get count => _count;

  // 只写
  set increment(int delta) {
    _count += delta;
  }
}

var c = Counter();
print(c.count);    // 0
c.increment = 5;   // 相当于调用 setter,_count += 5
print(c.count);    // 5
// c.count = 10;   // 编译错误:没有对应 setter
// print(c.increment); // 编译错误:没有对应 getter

3. 带验证或计算逻辑

dart 复制代码
class Rectangle {
  double _width, _height;

  Rectangle(this._width, this._height);

  // 计算属性:无需存字段,每次都从宽高算
  double get area => _width * _height;

  // 带验证的 setter:宽度必须>0
  set width(double w) {
    if (w <= 0) throw ArgumentError('宽度必须大于0');
    _width = w;
  }

  set height(double h) {
    if (h <= 0) throw ArgumentError('高度必须大于0');
    _height = h;
  }
}

4. 顶层(或静态)getter/setter

除了类内部,你也可以在最外层定义顶层属性访问:

dart 复制代码
int _globalCache = 0;

int get globalCache => _globalCache;
set globalCache(int v) {
  _globalCache = v;
}

或者在类里定义静态访问器:

dart 复制代码
class Config {
  static String _env = 'prod';

  static String get env => _env;
  static set env(String e) {
    _env = e;
  }
}

5. 注意事项

  • get 必须返回值,不能有参数;set 必须是 void 且只接受一个参数。
  • 属性访问器在外看起来就像字段,调用时无需加 ()
  • 如果没有显式定义 getter 或 setter,Dart 会自动为公有字段生成默认的访问器。

小结

  • get foo => ...:定义一个可读属性
  • set foo(value) { ... } :定义一个可写属性
  • 可用于封装私有字段、添加验证逻辑、计算属性、顶层/静态配置等。

Dart的抽象类和方法

抽象类(abstract class

  • 定义方式 :在类名前加 abstract,例如 abstract class Study

  • 内容:可以包含

    • 抽象方法(无方法体,需要子类实现)
    • 具体方法(带方法体,可直接复用或重写)
  • 特性

    • 不能被直接实例化
    • 用于定义接口并提供部分实现

抽象方法

  • 定义方式 :在抽象类中声明方法但不写方法体,例如

    dart 复制代码
    abstract class Study {
      void study();    // 抽象方法
    }
  • 关键点

    • 无需不允许abstract 关键字修饰
    • 子类必须实现所有抽象方法,否则编译失败
    • 可以存在多个抽象方法,提供接口契约

抽象类的作用

  • 替代接口 :Dart 无独立 interface,抽象类既能定义契约,也能提供默认实现
  • 模板方法:把共通行为写在抽象类,变化部分留给子类
  • 代码组织:通过继承保持一致性,通过重写实现可扩展性

实现(继承)抽象类

  • 继承方式

    dart 复制代码
    class StudyDart extends Study {
      @override
      void study() { /* 实现抽象方法 */ }
    }
  • 须实现 :抽象类中声明的所有抽象方法

  • 可选重写:抽象类中已有具体实现的方法,可选择重写或直接复用

实例化

  • 抽象类 :不能 new Study()
  • 子类:只要实现完抽象方法,就可被实例化

特性 抽象类 抽象方法
定义关键字 abstract class ClassName { ... } 在抽象类中声明、不写方法体
方法体 可包含具体实现方法 允许方法体
实例化 不能被实例化 ------
子类要求 必须实现所有抽象方法,或自身也标记为 abstract 子类必须重写,否则编译报错
主要用途 定义接口+可选默认实现(替代接口) 强制子类提供特定行为

在Flutter中使用mixin

Mixin 的定义与特征 当我们想 "给任意类加一项新能力" ,又不希望因为这项能力去改变它们的继承层级,就非常适合用 Mixin。

  • 代码复用工具:可以把一组方法和属性"混入"多个类,避免多重继承的复杂性。
  • 必须继承自 Object :不能 extends 其他类,也无法调用 super
  • 无构造函数 :不能定义构造方法,也不能在 mixin 里调用 super()

如何创建与使用 Mixin

  1. 定义(Dart 3.0+ 必须)

    dart 复制代码
    mixin StudyMixin {
      void study2() {
        print('Mixin: study2 方法被调用');
      }
    }
  2. 命名规范

    • 推荐以 Mixin 为后缀,比如 StudyMixinLoggerMixin,便于识别。
  3. 使用

    dart 复制代码
    class Person {
      final String name;
      Person(this.name);
    }
    
    // Test 继承自 Person,并"with" StudyMixin
    class Test extends Person with StudyMixin {
      Test(String name): super(name);
    
      void demo() {
        print('$name 开始 Demo');
        study2(); // 调用 mixin 方法
      }
    }

完整示例

dart 复制代码
// 1. 定义一个 Mixin 
mixin StudyMixin {
  void study2() {
    print('StudyMixin → study2() 被调用');
  }
}

// 2. 基础类
class Person {
  final String name;
  Person(this.name);
}

// 3. 混入 Mixin 的子类
class Test extends Person with StudyMixin {
  Test(String name) : super(name);

  void demo() {
    print('$name: demo 方法开始');
    study2(); // Mixin 提供的方法
  }
}

void main() {
  final t = Test('Alice');
  t.demo();
  // 输出:
  // Alice: demo 方法开始
  // StudyMixin → study2() 被调用
}

注意事项

  • Dart 3.0+ 必须mixin 关键字定义。
  • Mixin 中不能有构造函数,也不可调用 super()
  • 如果需要对宿主类有类型限制,可使用 on 关键字做约束(例如 mixin M on SomeBase)。

Dart泛型在Flutter中的应用

1. 泛型概述

泛型(Generics)允许在类、接口或方法中使用类型参数,使代码在保持类型安全的前提下具备更高的复用性。Dart 中使用尖括号 <> 来声明类型参数。


2. 泛型类:Cache<T> 示例

dart 复制代码
class Cache<T> {
  final Map<T, T> _storage = {};

  /// 设置缓存
  void setItem(T key, T value) {
    _storage[key] = value;
  }

  /// 获取缓存,若不存在则返回 null
  T? getItem(T key) {
    return _storage[key];
  }
}
  • 说明

    • T 为类型参数,可以是任意类型。
    • 内部使用 Map<T, T> 存储键值对。
    • getItem 返回可空类型 T?,避免直接抛出异常。

3. 泛型方法示例

dart 复制代码
/// 从列表中取出第一个元素
T? getFirst<T>(List<T> items) {
  return items.isNotEmpty ? items.first : null;
}
  • 说明

    • 方法前也可声明类型参数 <T>,根据调用时传入的类型自动推断。

4. 实际应用:存储不同类型

dart 复制代码
void main() {
  // 存储字符串
  final stringCache = Cache<String>();
  stringCache.setItem('greet', 'hello');
  print(stringCache.getItem('greet')); // hello

  // 存储整数
  final intCache = Cache<int>();
  intCache.setItem(1, 100);
  print(intCache.getItem(1)); // 100

  // 泛型方法
  print(getFirst<int>([10, 20, 30])); // 10
}

5. 高级应用:泛型约束与通用接口

  • 泛型约束

    限制类型参数必须是某个类的子类或实现某个接口。例如,只缓存 num 类型及其子类:

    dart 复制代码
    class NumCache<T extends num> {
      final Map<String, T> _map = {};
      void set(String key, T value) => _map[key] = value;
      T? get(String key) => _map[key];
    }
  • 通用接口

    定义一个仓储接口,并让具体类实现:

    dart 复制代码
    abstract class Repository<T> {
      T fetchById(String id);
      void save(T item);
    }
    
    class User { final String name; User(this.name); }
    
    class UserRepository implements Repository<User> {
      @override
      User fetchById(String id) => User('User-$id');
    
      @override
      void save(User item) {
        // 保存逻辑
      }
    }

有哪些可以用在Flutter上的编程技巧?

  1. 面向对象编程技巧

    • 封装、继承和多态是面向对象设计的关键概念。
    • 推荐将代码组织成小的可复用模块或方法,以提高代码的可维护性和复用性,并建议单个方法的长度不超过100行。
    • 使用"点"操作符来查看API文档,这有助于理解每个方法的具体功能。
  2. Dart编程技巧

    • 安全调用(Null Safety) :使用?.操作符处理可能为空的对象,避免空指针异常。
    • 默认值设置 :利用??运算符为可能为空的变量指定一个默认值。
    • 简化判断逻辑:采用集合或数组的方式优化多个条件的判断流程,使得代码更加简洁高效。

Dart高效编程技巧

相关推荐
dualven_in_csdn1 小时前
搞了两天的win7批处理脚本问题
java·linux·前端
你的人类朋友2 小时前
✍️【Node.js程序员】的数据库【索引优化】指南
前端·javascript·后端
小超爱编程2 小时前
纯前端做图片压缩
开发语言·前端·javascript
应巅3 小时前
echarts 数据大屏(无UI设计 极简洁版)
前端·ui·echarts
Jimmy3 小时前
CSS 实现描边文字效果
前端·css·html
islandzzzz4 小时前
HMTL+CSS+JS-新手小白循序渐进案例入门
前端·javascript·css·html
Senar4 小时前
网页中如何判断用户是否处于闲置状态
前端·javascript
很甜的西瓜4 小时前
typescript软渲染实现类似canvas的2d矢量图形引擎
前端·javascript·typescript·图形渲染·canvas
Allen Bright4 小时前
【CSS-9】深入理解CSS字体图标:原理、优势与最佳实践
前端·css
阿芯爱编程5 小时前
最长和谐子序列,滑动窗口
前端·javascript·面试